Première partie du tutoriel complet sur l’installation d’un serveur mail. Nous allons y voir la mise en place d’un serveur LDAP destiné à stocker les informations nécessaires au bon fonctionnement de notre serveur de messagerie.
Jusqu’à présent, pour mon serveur de messagerie, je passais par un stockage des comptes dans une base SQL. Ayant mis en place un serveur LDAP, j’ai voulu greffer ma messagerie dessus.
Il faut savoir qu’il n’y a pas une façon unique de faire. Les infos peuvent être organisées autrement, par exemple, les comptes utilisateurs peuvent être dans l’OU mail et différents des comptes présents dans l’OU people. Ou au contraire, on peut rassembler les infos de chaque domaine dans son OU.
L’important au final étant que vos requêtes Ldap puissent sortir les infos, à savoir : les domaines gérés, les alias et les comptes utilisateurs.
Mon modèle n’est pas forcement le plus simple ou le plus adapté à votre cas, mais le changer ne demande que peu d’efforts, l’important étant surtout de comprendre la logique.
Table des matières
Serveur de Messagerie ldap postfix dovecot rspamd fail2ban
B – Droits d’accès à la configuration du serveur
III – Explication de l’organisation LDAP
D – Les nouveaux attributs des utilisateurs
II – Les ports dans le domaine du mail
9 – Fichier 20-managesieve.conf
I – Sécurisation SMTPS et Submission
A – Filtrage des fichiers à risque
B – Supprimer les informations sensibles
V – Apprentissage par déplacement.
Fail2ban, configuration pour Postfix et Dovecot
I – Présentation et installation
Fail2ban et python pour piloter un Firewall central
Pour le serveur LDAP, je pars sur une VM fraîchement installée puis une mise à jour et on installe le paquet slapd et le paquet ldap-utils contenant les outils pour modifier le Ldap.
# apt-get update && apt-get upgrade
# apt-get install slapd ldap-utils
La, vous répondez comme cela :
Omit OpenLDAP server configuration? No
DNS domain name: debugo.fr
Organization name? Debugo
Administrator password: PASSWORD
Confirm password: PASSWORD
Database backend to use: MDB
Do you want the database to be removed when slapd is purged? YES
Ensuite, un petit tour dans le fichier /etc/ldap/ldap.conf pour le configurer comme il faut (utilisé par les outils ldap pour modifier le LDAP en ligne de commande) :
BASE dc=debugo,dc=fr
URI ldap://IP.MACHINE/
On relance openldap :
# service slapd restart
On test avec :
# ldapsearch -xLLL
Avant tout, on va créer des répertoires pour stocker nos fichiers :
# mkdir /root/ldap
# cd /root/ldap
Afin d’éviter d’avoir à toujours retaper le mot de passe admin lors des commandes, nous allons l’enregistrer dans un fichier.
On va créer un fichier /root/pwdldap et mettre le mot de passe dedans :
# echo -n "mdpadmin" > /root/pwdldap
# chmod 600 /root/pwdldap
On test :
# ldapsearch -x -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b dc=debugo,dc=fr
Par défaut, l’accès à la configuration n’est pas possible en passant par le socket réseau avec le compte admin (et on en aura besoin pour ajouter notre schéma).
Créez le fichier LDIF /root/ldap/acces-conf-admin.ldif, et insérez :
dn: olcDatabase={0}config,cn=config
changeType: modify
add: olcAccess
olcAccess: to * by dn.exact=cn=admin,dc=debugo,dc=fr manage by * break
Injectez :
# cd /root/ldap
# ldapmodify -Y external -H ldapi:/// -f acces-conf-admin.ldif
Et l’on peut voir que c’est bon avec :
# ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap -b cn=config
On va ajouter notre compte système viewer dans un fichier viewer.ldif. Ce compte servira à Postfix et Dovecot, pour qu’ils puissent lire les infos du Ldap.
dn: cn=viewer,ou=system,dc=debugo,dc=fr
objectClass: simpleSecurityObject
objectClass: organizationalRole
cn: viewer
description: LDAP viewer
userPassword: passview
Et on l’injecte :
# ladd -f viewer.ldif
Puis on va modifier les Acls afin de donner le droit au compte viewer de lire les passwords.
Fichier acl.ldif :
dn: olcDatabase={1}mdb,cn=config
changetype: modify
replace: olcAccess
olcAccess: to attrs=userPassword by self write by anonymous auth by dn="cn=viewer,ou=system,dc=debugo,dc=fr" read by dn="cn=admin,dc=debugo,dc=fr" write by * none
olcAccess: to dn.base="dc=debugo,dc=fr" by users read
olcAccess: to * by self write by dn="cn=admin,dc=debugo,dc=fr" write by * read by anonymous none
On injecte :
# ldapmodify -Q -Y EXTERNAL -H ldapi:/// -f acl.ldif
Nous allons utiliser énormément les commande fournies par ldap-utils. Du coup, afin d’aller plus vite nous allons créer des alias.
Éditez le fichier /root/.bashrc pour y ajouter :
alias lmodif='ldapmodify -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
alias lsearch='ldapsearch -xLLL -H ldap://localhost -D cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
alias ladd='ldapadd -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
alias ldel='ldapdelete -cxWD cn=admin,dc=debugo,dc=fr -y /root/pwdldap'
Pour une prise en compte immédiate :
# source /root/.bashrc
Je ne fais qu’effleurer la configuration d’un serveur LDAP. Pour plus de détails, je vous invite fortement à consulter ma série d’articles sur le Ldap.
On va créer nos OUs de base dans un fichier ou.ldif :
dn: ou=people,dc=debugo,dc=fr
ou: people
objectClass: organizationalUnit
dn: ou=system,dc=debugo,dc=fr
ou: people
objectClass: organizationalUnit
Et on l’injecte :
# ladd -f ou.ldif
Avant de passer à la création de nos utilisateurs, petit point sur le stockage des mots de passe dans LDAP.
Par défaut, ils sont stockés en clair. Dans la suite du tutoriel, cela pose soucis avec le bind de Dovecot. Puis stocker en clair, c’est pas top.
Il est possible de force le hash avec l’overlay Ppolicy. A vous de configurer cela si vous voulez.
Sinon, à la main :
# slappasswd -h {SSHA}
Renseignez le pass deux fois et vous obtiendrez le hash en SSHA, hash qu’il faudra mettre dans le champ userPassword.
Puis nous passons à un premier utilisateur dans un fichier usertoto.ldif :
dn: uid=toto,ou=people,dc=debugo,dc=fr
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: toto
sn: toto
givenName: toto
cn: toto
displayName: toto
userPassword: {SSHA}.....
mail: toto@domaine1.fr
et un second dans un fichier usertata.ldif :
dn: uid=tata,ou=people,dc=debugo,dc=fr
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
uid: tata
sn: tata
givenName: tata
cn: tata
displayName: tata
userPassword: {SSHA}.....
mail: tata@domaine1.fr
Pour terminer en injectant les deux :
# ladd -f usertoto.ldif
# ladd -f usertata.ldif
Jusque la, je stocke mes comptes utilisateur. Ceci dit, il me manque des attributs, que je rajouterais via un schéma personnel.
Au niveau domaine, j’en ai deux : domaine1.fr, domaine2.fr et je gère deux compte mails toto@domaine1.fr et tata@domaine1.fr. Toutes les autres adresses de domaine1 et domaine2 (par ex ccc@domaine1.fr, aaa@domaine2.fr, bbb@domaine2.fr, etc.. seront renvoyés soit vers toto@domaine1.fr soit vers tata@domaine1.fr.
Pour la gestion domaines et alias, j’ai donc choisi de faire de la sorte :
dc=debugo,dc=fr
ou=people,dc=debugo,dc=fr
"Stockage de mes utilisateurs"
ou=mail,dc=debugo,dc=fr
ou=domaine1.fr,
cn=alias1@domaine1.fr,ou=domaine1.fr,ou=mail,dc=debugo,dc=fr
attr: mailfrom: alias@domaine1.fr
attr: mailto: toto@domaine1.fr
etc...
ou=domaine2.fr,
etc...
Chaque domaine sera une OU dans une nouvelle OU créée pour l’occasion.
Et dans chaque OU, je crée des entrées correspondants aux alias, la aussi avec l’aide de schéma supplémentaire
Mes domaines auraient très bien pu être non pas des OU mais des entrées, au niveau de l’OU mail et les alias définies par des attributs soit dans ces entrées soit dans les entrées des users. Je vous le disais, on peut vraiment faire comme on veut.
On va créer un fichier schema.ldif :
dn: cn=maildebugo,cn=schema,cn=config
objectClass: olcSchemaConfig
cn: maildebugo
olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.20 NAME 'mailaccountquota' DESC 'Quota Mail' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.21 NAME 'mailaccountactif' DESC 'Mail Actif' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.40 NAME 'mailaliasfrom' DESC 'Mail From' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.41 NAME 'mailaliasto' DESC 'Mail To' EQUALITY caseExactMatch SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.42 NAME 'mailaliasactif' DESC 'Alias Actif' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.60 NAME 'maildomain' DESC 'Domaine' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcAttributeTypes: ( 1.3.6.1.4.1.99999.2.2.61 NAME 'maildomainactif' DESC 'Domaine Actif' EQUALITY caseExactMatch SINGLE-VALUE SYNTAX 1.3.6.1.4.1.1466.115.121.1.15 )
olcObjectClasses: ( 1.3.6.1.4.1.99999.2.1.20 NAME 'mailaccountdebugo' SUP TOP AUXILIARY MUST ( mailaccountquota $ mailaccountactif))
olcObjectClasses: ( 1.3.6.1.4.1.99999.2.1.40 NAME 'mailaliasdebugo' SUP TOP STRUCTURAL MUST ( cn $ mailaliasfrom $ mailaliasto $ mailaliasactif))
olcObjectClasses: ( 1.3.6.1.4.1.99999.2.1.60 NAME 'maildomaindebugo' SUP TOP AUXILIARY MUST ( maildomain $ maildomainactif))
Vous voyez trois séries de chiffres dans le fichier.
L’OID 1.3.6.1.4.1.99999.2.2.x correspond à la hiérarchie de mes attributs (la branche 1.3.6.1.4.1 est la branche dédiée aux OID privés : voir ici).
Le 99999 devrait être dans l’idéal remplacé par le PEN que vous pouvez obtenir sur cette page. Si vous ne destinez pas votre schéma a être public, ça n’a pas trop d’importance, mais attention à ne pas prendre un numéro déjà existant si un jour vous importez un schéma avec ce numéro, bref, vous voyez le topo. J’ai fais la demande, j’ai eu mon PEN en 72h je crois…
L’OID 1.3.6.1.4.1.99999.2.1.x est sur le même modèle mais définit un objet.
L’OID 1.3.6.1.4.1.1466.115.121.1.15 correspond à la définition d’une directory string (chaîne de caractère), je fais simple et prend ce type de donnée pour mes nouveau attributs.
Ce schéma est au final assez simple, je rajoute trois nouvelles classe d’objets : mailaccountdebugo, maildomaindebugo et mailaliasdebugo (qui à la particularité d’être structural, c’est à dire que ce pourra être une entrée sans ajout d’autre classe (par ex, inetogperson, etc…).
Chaque classe possède des attributs obligatoire (MUST).
L’attribut mailaliasto est le seule à ne pas avoir SINGLE-VALUE, en effet, un alias peut renvoyer vers plusieurs bals.
Le puriste et fin connaisseur des schémas de base d’OpenLdap me dira : « Oui, on peut faire tout ça sans rajouter de nouveaux schémas, en utilisant des attributs qui existent déjà ! »
Oui, mais dans mon cas, cela ne me convenait pas (les alias dans l’entrée de l’user, pourquoi pas, mais pour ensuite dire s’ils sont actifs, etc.., c’est compliqué). Et puis c’est l’occasion de faire des manipulations sur le Ldap…
Bref, on va ajouter notre schéma :
# ladd -f schema.ldif
Ensuite, on va créer nos nouvelles OUs dans un fichier oumail.ldif :
dn: ou=mail,dc=debugo,dc=fr
ou: people
objectClass: organizationalUnit
dn: ou=domaine1.fr,ou=mail,dc=debugo,dc=fr
ou: domaine1.fr
objectClass: organizationalUnit
objectClass: maildomaindebugo
description: Domaine mail primaire
maildomain: domaine1.fr
maildomainactif: YES
dn: ou=domaine2.fr,ou=mail,dc=debugo,dc=fr
ou: domaine2.fr
objectClass: organizationalUnit
objectClass: maildomaindebugo
description: Domaine mail secondaire
maildomain: domaine2.fr
maildomainactif: YES
On injecte :
# ladd -f oumail.ldif
Puis on passe à la création des entrées pour les alias dans un fichier alias.ldif :
dn: cn=postmaster@domaine1.fr,ou=domaine1.fr,ou=mail,dc=debugo,dc=fr
objectclass: mailaliasdebugo
cn: postmaster@domaine1.fr
mailaliasfrom: postmaster@domaine1.fr
mailaliasto: toto@domaine1.fr
mailaliasactif: YES
dn: cn=postmaster@domaine2.fr,ou=domaine2.fr,ou=mail,dc=debugo,dc=fr
objectclass: mailaliasdebugo
cn: postmaster@domaine2.fr
mailaliasfrom: postmaster@domaine2.fr
mailaliasto: toto@domaine1.fr
mailaliasactif: YES
dn: cn=testalias@domaine1.fr,ou=domaine1.fr,ou=mail,dc=debugo,dc=fr
objectclass: mailaliasdebugo
cn: testalias@domaine1.fr
mailaliasfrom: testalias@domaine1.fr
mailaliasto: toto@domaine1.fr
mailaliasto: tata@domaine1.fr
mailaliasactif: YES
A vous bien sur de faire vos propres alias en fonction de vos besoins.
On injecte :
# ladd -f alias.ldif
Et pour finir, on va rajouter les attributs de la classe mailaccountdebugo à nos utilisateurs.
Fichier attrtoto.ldif :
dn: uid=toto,ou=people,dc=shyride,dc=org
changetype: modify
add: objectclass
objectclass: mailaccountdebugo
-
add: mailaccountquota
mailaccountquota: 0
-
add: mailaccountactif
mailaccountactif: YES
Fichier attrtata.ldif :
dn: uid=tata,ou=people,dc=shyride,dc=org
changetype: modify
add: objectclass
objectclass: mailaccountdebugo
-
add: mailaccountquota
mailaccountquota: 0
-
add: mailaccountactif
mailaccountactif: YES
On injecte ces deux fichiers :
# ladd -f atttoto.ldif
# ladd -f attrtata.ldif
Par la suite, pour ajouter un nouvel utilisateur, on pourra bien évidemment tout faire en un bloc :
dn: uid=new,ou=people,dc=debugo,dc=fr
objectclass: person
objectclass: organizationalPerson
objectclass: inetOrgPerson
objectclass: mailaccountdebugo
uid: new
sn: new
givenName: new
cn: new
displayName: new
userPassword: {SSHA}.....
mail: new@domaine1.fr
mailaccountquota: 0
mailaccountactif: YES
On peut déjà tester en listant par exemple les domaines gérés :
# lsearch -b "ou=mail,dc=debugo,dc=fr" "(&(objectClass=maildomaindebugo))" ou
Ou encore, pour savoir par exemple vers quelle bal renvoie l’alias postmaster@domaine1.fr :
# lsearch -b "ou=mail,dc=debugo,dc=fr" "(&(objectClass=mailaliasdebugo)(mailaliasfrom=postmaster@domaine1.fr))" mailaliasto
Voila qui termine la partie LDAP pour l’utilisation avec un serveur de messagerie. Je vous invite encore une fois à consulter mon tutoriel sur LDAP qui vous expliquera également comment modifier, supprimer des données dans l’annuaire (ainsi que plein d’autres choses ! )
Et sinon, on peut passer à la suite avec la mise en place de Postfix…
Seconde partie du tutoriel consacré à l’installation d’un serveur de messagerie.
Préalablement, nous avons installé et configuré le serveur Ldap. Dans cette partie, nous allons mettre en place nos certificats et procéder à la configuration de base de Postfix.
Avant de se lancer, il faut faire quelques manipulations.
Au niveau messagerie, si vous voulez que votre serveur puisse envoyer des mails sans que les autres le jette comme un malpropre, il y a un premier point important.
Il est nécessaire que son reverse dns soit correctement configuré : si on demande l’adresse de mail.domaine1.fr et qu’on a XXX.XXX.XXX.XXX, il faut qu’en demandant le reverse de XXX.XXX.XX.XXX on obtienne mail.domaine1.fr
Si vous avez déjà un autre reverse sur l’adresse, soit vous changez, mais bon… Soit vous prenez une nouvelle IP.
Étant chez Online, j’ai donc pris une nouvelle IP Failover ou j’ai configuré le reverse en mail.domaine1.fr.
Ensuite, elle est branché sur ma VM routeur sur le bridge br0 (avec la mac bien renseignée !).
Cette manipulation est identique à ce que je fais dans cet article (au final, mon routeur aura deux IPFO)
Sur le serveur dns, on va renseigner les nouveaux enregistrements dans le fichier de zone correspondant :
IN MX 10 mail.domaine1.fr
mail IN A IP.FO2
Le champ MX indique qu’il s’agit d’un serveur mail. Et ensuite, on définit simplement l’IP de mail.domaine1.fr.
Si on gère son dns (voir ici), on pense à incrémenter le serial et à recharger avec :
# rndc reload
Pour tester :
# dig domaine1.fr MX +short
Au niveau de notre routeur, on va indiquer les ports qu’on redirige en entrée :
iptables -t nat -A PREROUTING -d IP.FO2 -p tcp -m multiport --dports 25,80,143,465,587,993,4190 -j DNAT --to-destination ip.interne
iptables -t filter -A FORWARD -p tcp -d ip.interne -m multiport --dports 25,80,143,465,587,993,4190 -j ACCEPT
•.25 -> SMTP
•.465 -> SMTPS
•.587 -> SUBMISSION
•.143 -> IMAP
•.993 -> IMAPS
•.4190 -> Managesieve
Et pour terminer, on redirige aussi le port 80 (Web) car pour le certificat Let’s Encrypt, le serveur aura besoin de monter un serveur web temporaire accessible de l’extérieur.
En sortie :
iptables -t filter -A FORWARD -p tcp -s ip.interne -m multiport --dports 25,53,80,443 -j ACCEPT
iptables -t nat -A POSTROUTING -s ip.interne -p tcp -m multiport --dports 25,53,80,443 -j SNAT --to IP.FO2
Juste le port SMTP et les ports Web. Ajoutez aussi le DNS si vous n’avez pas de resolver interne (dans ce cas, corrigez moi ça en suivant ceci )
On peut dire que la, c’est un peu le boxon…
Nous avons:
•.Le port 25, SMTP, utilisé pour l’envoi de mail vers le serveur depuis d’autres serveurs.
•.Le port 110, POP, désuet, utilisé pour rapatrier les mails sur un logiciel client.
•.Le port 143, IMAP, permet de consulter sa messagerie, depuis un logiciel client, un webmail, un smartphone, etc…
A cela se rajoute leurs pendants sécurisés :
•.Le port 465, SMTPS (chiffrement SSL/TLS), utilisé par les logiciels clients pour envoyer des mails vers le serveur.
•.Le port 587, SUBMISSION (chiffrement STARTLS), lui aussi utilisé par les logiciels clients pour envoyer des mails vers le serveur.
•.Le port 995, POPS (chiffrement SSL/TLS)
•.Le port 993, IMAPS (chiffrement SSL/TLS)
Les ports 110 et 143 peuvent voir leur connexion chiffré avec STARTTLS, aussi appelé EXPLICIT SSL/TLS.
Le client se connecte au serveur en non chiffrée et il négocie le chiffrement juste après. Cette phase se produisant au tout début, toutes les infos sont ensuite chiffrées.
Sur les ports 465 et 587, utilisant le chiffrement SSL/TLS, la sécurité est établie dès le début. On parle aussi de IMPLICIT SSL/TLS.
Pour donner une image, en SSL/TLS, on a une conversion normal dans une canal chiffrée et en STARTTLS, on a une conversation chiffrée dans un canal en clair…
Alors pourquoi garder les deux ?
Les RFC recommandent maintenant de tout faire en SSL/TLS (un potentiel Man-in-the-middle est possible en STARTTLS.)
Mais de vieux clients peuvent encore nécessiter la présence des ports avec TLS explicite… Du coup, bah, vous faites comment vous le sentez…
Pour le tuto, j’ai choisie de tout mettre dans la configuration pour vous montrer. Perso, en prod, je pars sur du SSL/TLS.
Pour le port 25, Le STARTTLS est proposé si le MX distant le supporte.
Pour plus de détails sur comment on en est arrivés la, je vous conseille de lire cet article.
Sur une nouvelle VM :
# apt-get install postfix postfix-ldap ca-certificates
Lors de l’installation de Postfix, répondez :
Internet Site
mail.domaine1.fr
Pour ca-certificates, il est toujours bon de l’avoir, et il nous sera utile pour l’installation de Rspamd plus tard.
Et on installe dans la foulée Dovecot :
# apt-get install dovecot-core dovecot-imapd dovecot-ldap dovecot-managesieved dovecot-sieve dovecot-lmtpd
A vrai dire, je l’installe de suite car le script de mise à jour du certificat redémarre les services postfix et dovecot , donc autant éviter des erreurs dès le début…
On va de suite gérer le certificat avec acme.sh (client pour Let’s Encrypt, plus d’informations dans mon article) :
# apt-get install git socat
Installons maintenant acme.sh :
# cd
# mkdir sources
# cd sources/
# git clone https://github.com/Neilpang/acme.sh.git
# cd ./acme.sh
# ./acme.sh --install
On recharge le bash :
# source /root/.bashrc
Et on lance la création du certificat :
# acme.sh --issue -k 4096 --standalone -d mail.domaine1.fr --log
On installe le certificat :
# mkdir /etc/ssl/private/domaine1.fr
# acme.sh --installcert -d mail.domaine1.fr --cert-file /etc/ssl/private/domaine1.fr/cert.pem --key-file /etc/ssl/private/domaine1.fr/key.pem --ca-file /etc/ssl/private/domaine1.fr/ca.pem --fullchain-file /etc/ssl/private/domaine1.fr/fullcert.pem --reloadCmd 'service postfix reload && service dovecot reload'
On génère nos clés DH :
# openssl dhparam -out /etc/ssl/private/domaine1.fr/dh512.pem 512
# openssl dhparam -out /etc/ssl/private/domaine1.fr/dh2048.pem 2048
# chmod 644 /etc/ssl/private/domaine1.fr/dh{512,2048}.pem
La commande installcert met également en place une tache cron pour le renouvellement automatique de votre certificat qui du coup, renouvelle, copie ou il faut et relance, parfait !
On va éditer le fichier /etc/postfix/main.cf pour le mettre à notre sauce :
mynetworks = 10.0.0.0/8
inet_interfaces = all
inet_protocols = ipv4
smtpd_banner = $myhostname ESMTP $mail_name (Debian/GNU)
biff = no
append_dot_mydomain = yes
readme_directory = no
compatibility_level = 2
notify_classes = bounce, delay, policy, protocol, resource, software
myhostname = mail.domaine1.fr
mydestination = $myhostname, mail, localhost.localdomain, localhost
myorigin = $myhostname
disable_vrfy_command = yes
strict_rfc821_envelopes = yes
show_user_unknown_table_name = no
message_size_limit = 0
mailbox_size_limit = 0
allow_percent_hack = no
swap_bangpath = no
recipient_delimiter = +
alias_maps = hash:/etc/aliases
alias_database = hash:/etc/aliases
broken_sasl_auth_clients=yes
smtp_tls_security_level = may
smtp_tls_session_cache_database = btree:${data_directory}/smtp_tlscache
smtpd_tls_loglevel = 1
smtpd_tls_security_level = may
smtpd_tls_auth_only = yes
smtpd_tls_key_file = /etc/ssl/private/domaine1.fr/key.pem
smtpd_tls_cert_file = /etc/ssl/private/domaine1.fr/cert.pem
smtpd_tls_CAfile = /etc/ssl/private/domaine1.fr/fullcert.pem
smtpd_tls_protocols = !SSLv2 !SSLv3
smtpd_tls_mandatory_protocols = !SSLv2 !SSLv3
smtpd_tls_mandatory_ciphers = high
smtpd_tls_eecdh_grade = strong
smtpd_tls_dh512_param_file = /etc/ssl/private/domaine1.fr/dh512.pem
smtpd_tls_dh1024_param_file = /etc/ssl/private/domaine1.fr/dh2048.pem
smtpd_tls_session_cache_database = btree:${data_directory}/smtpd_tlscache
smtpd_tls_session_cache_timeout = 3600s
smtpd_tls_received_header = yes
smtpd_sasl_auth_enable = yes
smtpd_sasl_path = private/auth
smtpd_sasl_type = dovecot
smtpd_sasl_security_options = noanonymous, noplaintext
smtpd_sasl_tls_security_options = noanonymous
tls_preempt_cipherlist = yes
tls_high_cipherlist = ALL EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !MEDIUM !3DES !MD5 !EXP !PSK !SRP !DSS !RC4
tls_ssl_options = no_ticket, no_compression
smtpd_helo_required = yes
smtpd_client_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_unknown_reverse_client_hostname,
reject_unauth_pipelining
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_invalid_helo_hostname,
reject_non_fqdn_helo_hostname,
reject_unauth_pipelining
smtpd_sender_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_sender,
reject_unknown_sender_domain,
reject_unauth_pipelining
smtpd_relay_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
###
# VITAL, empêche l'open relay
reject_unauth_destination
###
smtpd_recipient_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_non_fqdn_recipient,
reject_unknown_recipient_domain,
reject_unauth_pipelining
smtpd_data_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
reject_multi_recipient_bounce,
reject_unauth_pipelining
virtual_transport = lmtp:unix:private/dovecot-lmtp
virtual_mailbox_domains = ldap:/etc/postfix/ldap/virtual_domains.cf
virtual_mailbox_maps = ldap:/etc/postfix/ldap/virtual_mailbox.cf
virtual_alias_maps = ldap:/etc/postfix/ldap/virtual_alias.cf
Quelques explications :
append_dot_mydomain = yes
ajoute le domaine au mail locaux qui sont envoyés (si un mail local est envoyé depuis un service sur le serveur, genre cron, etc… il sera de la forme root@mail.domaine1.fr au lieu de root@mail).
Centralisant tous mes mails, éventuellement d’autres serveur, c’est une info dont j’ai besoin (on peut aussi réécrire l’expéditeur, etc..).
notify_classes = bounce, delay, policy, protocol, resource, software
Définit les messages d’erreurs que recoit le postmaster. A affiner selon ce que vous voulez. Voir la doc de Postfix pour plus de détails.
myhostname = mail.domaine1.fr
mydestination = $myhostname, mail, localhost.localdomain, localhost
Le nom de votre serveur de mail. Peut être différent, mais dans mon cas, vu ma config Dns, de l’extérieur ou de l’interieur, ca reste le meme nom.
Ensuite, les destinations qu’il accepte. On ne liste ici aucun domaine qu’on gère, ceux ci sont déclarés dans les alias virtuels.
Pour la partie SSL/TLS/SALS on remarque deux groupes d’options : smtp_* et smtpd_*
Smtp concerne la patie client de postfix, c’est à dire celle qui envoie les mails aux autres serveurs SMTP (aussi appelés MX).
Smtpd concerne la partie serveur, celle qui recoit les mails, soit des clients, soit des autres MX.
smtp_tls_security_level = may
indique que le client SMTP de postfix, quand il se connecte à un autre MX, supporte le TLS.
smtpd_tls_security_level = may
indique que le serveur SMTP de Postfix, quand il reçoit une connexion d’un client (mx ou soumis), supporte le TLS.
On le laisse à may pour indiquer que c’est possible sans être obligatoire. On le surchargera dans le fichier master.cf
Ne pas confondre aussi _sasl_ et _tls_ ! _sasl_ concerne l’authentification de nos utilisateusr (via Dovecot) et _tls_ le chiffrement des communications.
smtpd_tls_auth_only = yes
indique que si l’authentification est utilisé, on doit forcement être en SSL (ou TLS, ca revient au meme.)
Pour le reste, c’est du classique.
J’ai hésité à commenter toutes les restrictions… mais la doc de Postfix à ce sujet vous aidera à ma place.
Ce sont de bonnes restrictions pour commencer: elles permettent déjà de rejeter quelques tentative de spams.
Dans la partie IV du tuto, nous verrons plus en détails comment améliorer cela.
Un point important à connaitre : les permit ou reject sont testés dans l’ordre et dès que l’un match, cela stop pour la restriction en cours. L’ordre à donc une importance.
Grosso modo, pour chaque restriction, à chaque fois, j’autorise mon réseau local, mes utilisateurs authentifiés (mails soumis) et rejete les trucs mal fagotés…
On va ensuite modifier le fichier /etc/postfix/master.cf au début :
submission inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
On active submission, et on surchage (-o le parametre smtpd_tls_security_level à encrypt pour forcer le tls.
Un peu plus bas, on va activer le smtps :
smtps inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_wrappermode=yes
Le reste ne change pas.
Pourquoi Postfix utilise deux fichiers de configuration ?
Le fichier main.cf définit les options générales de Postfix. Le fichier master.cf, lui sert à gérer les sous process de Postfix et permet de modifier certains paramètres du fichier main.cf en les surchargeant (option -o).
On va créer nos fichiers chargé de faire la liaison avec le serveur ldap et les ranger :
# mkdir /etc/postfix/ldap
# cd /etc/postfix/ldap
Fichier virtual_domains.cf :
server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = ou=mail,dc=debugo,dc=fr
scope = sub
query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))
result_attribute = maildomain
Fichier virtual_mailbox.cf :
server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = ou=people,dc=debugo,dc=fr
scope = sub
query_filter = (&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES))
result_attribute = mail
Et le fichier virtual_alias.cf :
server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = ou=mail,dc=debugo,dc=fr
scope = sub
query_filter = (&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES))
result_attribute = mailaliasto
Pour des explications sur les filtres, vous en aurez dans la partie suivante, consacrée à Dovecot.
On sécurise :
# chmod 640 /etc/postfix/ldap/
# chown :postfix /etc/postfix/ldap/*
Puis on recharge Postfix :
# postfix reload
Et on peut tester les liens avec le ldap :
# postmap -q domaine1.fr ldap:/etc/postfix/ldap/virtual_domains.cf
nous retourne le domaine s’il existe.
# postmap -q postmaster@domaine1.fr ldap:/etc/postfix/ldap/virtual_alias.cf
donne le compte vers le lequel est envoyé l’alias.
# postmap -q toto@domaine1.fr ldap:/etc/postfix/ldap/virtual_mailbox.cf
nous retourne le mail s’il existe.
Il reste un dernier petit point, les alias locaux de la machine.
Comme je l’ai dis avant, je veux qu’à terme, ce serveur mail gère également les mails de mes autres vm pour tout centraliser.
Et je veux tout rapatrier sur mon adresse mail toto@domaine1.fr.
On édite le fichier /etc/aliases pour y mettre :
postmaster: postmaster@domaine1.fr
root: toto@domaine1.fr
Pour mémoire, postmaster@domaine1.fr est défini comme un alias de toto@domaine1.fr dans le ldap.
On exécute la commande :
# newaliases
pour convertir cela en fichier un fichier compréhensible de postfix et on le recharge :
# postfix reload
Postfix est opérationnel. Vous voyez, ce n’est pas si terrible ! On ne fait qu’effleurer la configuration, la documentation de Postfix est très complète et on peut configurer plein de scénarios…
Maintenant pour le tester, comme nous n’avons pas encore Dovecot derriere, on va se contenter de juste tester la communication d’un MX vers le nôtre :
Le site https://www.checktls.com/TestReceiver permet de faire cette vérification, et l’on voit de suite si le TLS est bon. On peut aussi classiquement en telnet, mais c’est… long…
Le site https://mxtoolbox.com/ est très pratique également.
Ha oui, au passage, le fichier clé pour debug, c’est bien évidement le fidèle :
/var/log/mail.log
Voila qui termine pour le moment le sujet Postfix. Dans la partir suivant, nous allons mettre en place Dovecot.
Nous allons créer l’utilisateur virtuel vmail ainsi que le répertoire qui stockera les mails :
# groupadd -g 11111 vmail
# useradd -g vmail -u 11111 vmail -d /home/vmail -m
# chown vmail: /home/vmail -R
# chmod 770 /home/vmail
Bien sur, dans l’idéal, ce stockage est redondant, etc… La, on simplifie, le reste est déjà conséquent…
Concernant la configuration de Dovecot, celui ci à la mauvaise idée de tout éclater dans une foultitude de fichiers.
Avant tout, faisons donc du tri…
# cd /etc/dovecot/conf.d
# rm 10-director 10-tcpwrapper 90-acl auth-*
et dans le répertoire /etc/dovecot :
# cd /etc/dovecot
# rm dovecot-dict-* dovecot-sql.conf.ext dovecot-ldap.conf.ext
On passe maintenant à la configuration. On va éditer le fichier /etc/dovecot/dovecot.conf et tout remplacer par :
protocols = imap lmtp
!include conf.d/*.conf
Oui, c’est concis, le reste sera dans le sous répertoire conf.d :
# cd /etc/dovecot/conf.d
Et la pour chaque fichier, remplacez tout son contenu par ce que je vous donne.
auth_cache_size = 0
auth_cache_ttl = 1 hour
auth_cache_negative_ttl = 1 hour
auth_mechanisms = plain
passdb {
driver = ldap
args = /etc/dovecot/dovecot-ldap-pass.conf.ext
}
userdb {
driver = prefetch
}
userdb {
driver = ldap
args = /etc/dovecot/dovecot-ldap-user.conf.ext
}
Dans ce fichier, on déclare la façon dont Dovecot récupère les infos. On reviendra plus en détail dessus après…
#log_path = syslog
#debug_log_path =
#syslog_facility = mail
#auth_verbose = no
#auth_verbose_passwords = no
#auth_debug = no
#auth_debug_passwords = no
#mail_debug = no
#verbose_ssl = no
plugin {
#mail_log_events = delete undelete expunge copy mailbox_delete mailbox_rename
# Available fields: uid, box, msgid, from, subject, size, vsize, flags
# size and vsize are available only for expunge and copy events.
#mail_log_fields = uid box msgid size
}
#log_timestamp = "%b %d %H:%M:%S "
#login_log_format_elements = user=<%u> method=%m rip=%r lip=%l mpid=%e %c
#login_log_format = %$: %s
#mail_log_prefix = "%s(%u): "
# %$ - Delivery status message (e.g. "saved to INBOX")
# %m - Message-ID
# %s - Subject
# %f - From address
# %p - Physical size
# %w - Virtual size
#deliver_log_format = msgid=%m: %$
Ici, auth_verbose et auth_debug sont bien pratiques en cas de soucis avec les connexions au LDAP, mail_debug pour les filtres Sieves (et autres, quota, etc…).
mail_home = /home/vmail/%d/%n
mail_location = maildir:~/mailbox
namespace inbox {
separator = /
inbox = yes
}
mail_uid = 11111
mail_gid = 11111
mail_privileged_group = vmail
first_valid_uid = 11111
last_valid_uid = 11111
first_valid_gid = 11111
last_valid_gid = 11111
mail_plugins = $mail_plugins
Emplacement des mails que je range en fonction du domaine et du nom. Ensuite,uig/gid de vmail… Rien de sorcier.
mail_fsync = never
service imap-login {
inet_listener imap {
port = 143
}
}
service imap {
service_count = 64
process_min_avail = 1
}
service lmtp {
unix_listener /var/spool/postfix/private/dovecot-lmtp {
group = postfix
mode = 0600
user = postfix
}
}
service auth {
unix_listener /var/spool/postfix/private/auth {
mode = 0660
user = postfix
group = postfix
}
}
service auth-worker {
user = vmail
}
Dans ce fichier, on déclare nos services : imap-login, imap, lmtp (utilisé pour le transfert de mails entre Postfix et Dovecot) et le service auth, qui service à Postfix pour authentifier les utilisateurs en SMTPS.
ssl = required
ssl_ca = </etc/ssl/private/domaine1.fr/ca.pem
ssl_cert = </etc/ssl/private/domaine1.fr/cert.pem
ssl_key = </etc/ssl/private/domaine1.fr/key.pem
ssl_dh_parameters_length = 2048
ssl_protocols = !SSLv3 !TLSv1 !TLSv1.1 TLSv1.2
ssl_cipher_list = ALL:!LOW:!SSLv2:!EXP:!aNULL
ssl_prefer_server_ciphers = yes
Le SSL, classique…
namespace inbox {
separator = /
mailbox Drafts {
auto = subscribe
special_use = \Drafts
}
mailbox Junk {
auto = subscribe
special_use = \Junk
}
mailbox Trash {
auto = subscribe
special_use = \Trash
}
mailbox Sent {
auto = subscribe
special_use = \Sent
}
mailbox Archive {
auto = subscribe
special_use = \Archive
}
}
La, on définit l’architecture de base de nos boites aux lettres. Création des répertoires spéciaux et auto souscription pour que l’utilisateur les voit de suite.
imap_idle_notify_interval = 30 mins
protocol imap {
mail_max_userip_connections = 50
mail_plugins = $mail_plugins imap_sieve
postmaster_address = postmaster@domaine1.fr
}
Configuration du protocole IMAP.
protocol lmtp {
mail_fsync = optimized
mail_plugins = $mail_plugins sieve
postmaster_address = postmaster@domaine1.fr
}
Configuration du protocole LMTP.
protocols = $protocols sieve
service managesieve-login {
inet_listener sieve {
port = 4190
}
service_count = 1
#process_min_avail = 0
#vsz_limit = 64M
}
Configuration de ManageSieve.
plugin {
sieve = file:~/sieve;active=~/.dovecot.sieve
sieve_before = /etc/dovecot/sieve-global
recipient_delimiter = +
sieve_quota_max_storage = 50M
}
Configuration de Sieve.
Pfff, c’était long hein ? Et bien, on a pas fini…
Avant de faire nos fichiers pour le Ldap, on va regarder à quoi devrait ressembler un dovecot-ldap.conf.ext qu’on peut rencontrer sur le grand internet, un exemple souvent cité (bon, les filtres sont les miens, mais c’est l’idée) :
uris = ldap://ip.interne
dn = cn=viewer,ou=system,dc=debugo,dc=fr
dnpass = passview
debug_level = 0
auth_bind = no
ldap_version = 3
base = ou=people,dc=debugo,dc=fr
scope = subtree
user_attrs = mailaccountquota=quota_rule=*:bytes=%$
user_filter = (&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))
pass_attrs = mail=user,userPassword=password
pass_filter = (&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))
C’est la que le auth_debug et mail_debug sont utiles … Mais un peu de théorie avant.
Dovecot utilise deux bases : passdb et userdb, déclarées dans cond.f/10-auth.conf ou j’utilise une petite astuce, le prefetch, pour éviter les doubles requêtes…
•.Lorsqu’un utilisateur se connecte en IMAP, passdb est utilisé pour vérifier l’utilisateur (login et mdp), puis userdb est appelé pour connaitre des infos supplémentaires sur l’user (d’où le prefetch).
•.Lorsqu’un mail arrive de Postfix à Dovecot via le protocole LMTP, c’est userdb qui est appelé pour connaitre l’utilisateur à qui remettre le mail d’où le second userdb car le premier, prefetch, ne contient rien pour le coup.
Il faut aussi savoir que Dovecot utilise des variables. Celles qui nous intéressent sont :
•.%u qui est le nom utilisateur complet fourni. Par exemple toto@domaine1.fr via un appel en Imtp (mail entrant) ou toto via l’Imap (client qui se connecte)
•.%n qui correspond à la partie utilisateur, ici : toto
•.%d qui correspond au domaine, ici : domaine1.fr
Ici, nous n’utiliserons que %u.
Au niveau du résultat ldap, l’ordre est :
attribut_ldap:attribut_dovecot
Et donc :
pass_attrs = mail=user,userPassword=password
indique que le champ mail de mon ldap correspond à l’utilisateur, du coup j’ai la bonne association.
Ensuite, au niveau du bind avec Ldap (la connexion avec Ldap), celui ci peut se faire de deux façons.
Cela permet de faire en sorte que le test du mot de passe se fasse directement avec le compte de l’utilisateur. Dovecot dans ce cas n’a pas besoin de lire le pass avec le compte viewer.
En contre partie, c’est plus lent, Dovecot attendant que la connexion avec le Ldap soit terminée avant de passer à la suivante.
La, il y a besoin que le compte viewer puisse lire le mot de passe (d’où les acls mises en place dans la partie LDAP). Ayant de toute façon besoin de ce compte pour d’autres applications, ça ne me dérange pas.
De plus, c’est asynchrone, Dovecot peut lancer plusieurs requêtes concomitantes sans attendre apres.
Bref, on part sur le second choix.
Cependant, cette config me pose encore un problème… Lorsque l’on se connecte en IMAP on se présente donc avec un simple toto par contre, lors du LMTP, le %u présenté par Postfix est le mail complet, toto@domaine1.fr et la, bah ça foire au niveau du filtre ldap, qui est pour mémoire :
(&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))
Que faire ? Refaire nos utilisateurs pour que leur uid soit leur mail ? Heu, c’est pas l’idée à la base…
Donc, pour ça, j’avais trouvé une première solution :
user_filter = (&(|(mail=%u)(uid=%u))(objectClass=mailaccountdebugo)(mailaccountactif=YES))
Ha, les filtres LDAP et leur notation préfixée. Si vous avez eu une calculette Sharp dans les 90’s, vous devez connaître (et être vieux 😉 ). Bon, elles utilisaient la notaion polonaise inverse où l’opérateur est à la fin, mais c’est la même idée… Si vous avez fait de l’algèbre booléenne ou bien joué avec les AND, OR, XOR, et NAND (du genre, comment faire un OR avec que des NAND, tables de vérités, etc..), et bien le + (ou) est remplacé par | et le . (et) par &.
On peut résumer :
(&(Bloc1)(Bloc2)(Bloc3)) -> On veut Bloc1 ET Bloc2 ET Bloc3
Bloc1=(|(A)(B)) -> A OU B
C’est beau hein ! Bah c’est balo car on en va pas l’utiliser. En effet, cela amène un effet de bord : je peux désormais me connecter à ma bal avec comme login mon mail….
Après, on aime ou on n’aime pas. Perso, je ne préfère pas laisser cette possibilité, pour éviter les vilains qui tenteraient de se connecter en connaissant déjà le login…
Apres tout, j’aurais pu en rester la et me dire tant pis, mais au final c’était ne pas vraiment comprendre Dovecot…
Il faut faire en sorte que les appels userdb et passdb soient distincts…
Pour la configuration, on aura donc deux fichiers :
/etc/dovecot/doveto-ldap-pass.conf.ext :
uris = ldap://ip.ldap
dn = cn=viewer,ou=system,dc=domaine1,dc=fr
dnpass = passview
debug_level = 0
auth_bind = no
ldap_version = 3
base = ou=people,dc=domaine1,dc=fr
scope = subtree
pass_attrs = mail=user,userPassword=password,mailaccountquota=userdb_quota_rule=*:bytes=%$
pass_filter = (&(uid=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))
La, on demande aussi au passage un attribut quota avec userdb userdb_quota_rule=*:bytes=%$ et qui sera utilisé dans le prefetch pour éviter de refaire une requête LDAP.
Et le fichier /etc/dovecot/dovecot-ldap-user.conf.ext :
uris = ldap://ip.ldap
dn = cn=viewer,ou=system,dc=domaine1,dc=fr
dnpass = passview
debug_level = 0
auth_bind = no
ldap_version = 3
base = ou=people,dc=domaine1,dc=fr
scope = subtree
user_attrs = mailaccountquota=quota_rule=*:bytes=%$
user_filter = (&(mail=%u)(objectClass=mailaccountdebugo)(mailaccountactif=YES))
La, on filtre sur le champ mail pour retrouver le compte correspondant.
On sécurise :
# chmod 600 /etc/dovecot/dovecot-ldap*
On va recharger Dovecot et regarder les logs voir si tout démarre bien :
# servive dovecot restart
# tail /var/log/mail.log -n 100
Dovecot permet donc de filtrer les messages en utilisant le protocole Sieve. Il les range à leur arrivée selon les règles, global et utilisateur.
Pour le global, on aura besoin que d’une seule règle : les messages marqués comme Spam sont dirigés dans le répertoire Spam.
Par la suite, chaque utilisateur pourra ajouter ses règles afin de filtrer comme il l’entend.
On a déjà activé Sieve au préalable. Il ne reste plus qu’à faire quelques opérations.
Pour le global :
mkdir /etc/dovecot/sieve-global
chown vmail /etc/dovecot/sieve-global
Nous rangerons nos scripts globaux dans ce répertoire, qui s’exécutera avant les filtres utilisateurs.
Si vous voulez faire les vérifications global apres, dans le fichier 90-sieve.conf, il faudra indiquer :
sieve_after = /etc/dovecot/sieve-global
Et on peut bien sûr combiner.
Créez ensuite le fichier /etc/dovecot/sieve-global/global.sieve avec le contenu qui suit :
require ["variables", "envelope", "fileinto", "mailbox", "regex", "subaddress", "body"];
if header :contains "X-Spam" "Yes" {
fileinto "Junk";
stop;
}
Tout bête, si le header contient X-spam à Yes, on le déplace dans les indésirables ( Le X-spam sera rajouté par Rspamd).
Le stop indique d’arrêter le traitement. En effet, si d’autres filtres (users ou globaux) matchent également, le message sera dupliqué.
Puis on change l’user et les droits :
#chown vmail: /etc/dovecot/sieve-global/global.sieve
#chmod 750 /etc/dovecot/sieve-global/global.sieve
On peut le compiler :
# sievec /etc/dovecot/sieve-global/global.sieve
qui donnera un fichier /etc/dovecot/sieve-global/global.svbin, version compilée de nos règles.
Cette opération est cependant facultative et elle sera de toute façon exécutée par Dovecot à la première occasion si vous le n’avez pas fait.
Si on le fait, on pense à modifier les droits :
# chown vmail /etc/dovecot/sieve-globa/global.svbin
Je serais même tenté de dire que la première fois, c’est mieux de laisser Dovecot le faire, en regardant les logs et avec l’option mail_debug = yes on voit très rapidement où se trouve le problème s’il y en a un (et généralement, ça chouine pour des histoires de permissions). Pour les filtres utilisateurs, c’est la même tambouille, Dovecot les compilant au moment ou il les charge, s’il n’existent pas ou sont obsolètes.
Pour modifier les filtres d’un utilisateur, on peut utiliser un webmail préalablement configuré. Pour le moment, je ne couvre pas cette partie (ce sera pour plus tard), donc pour le moment, on va plutôt passer par un client tel que Thunderbird.
Par défaut, Thunderbird ne les gère pas, mais il suffit de rajouter ce module complémentaire.
Ensuite menu Outils/Paramètres Sieve et activez la gestion de Sieve. Les paramètres sont identiques à l’IMAP, mais sur le port 4190.
Et ensuite dans le menu Outils/Filtres Sieve (M). Faites nouveau pour créer un nouveau fichier de règles.
Voila un exemple de règles :
require ["variables", "envelope", "fileinto", "mailbox", "regex", "subaddress", "body"];
if header :contains "subject" "Postfix SMTP server" {
fileinto "Serveur";
}
En cas de fautes, le plugin vous le signale. Il ne reste qu’a enregistrer. A noter : Sieve permet d’avoir plusieurs fichiers de filtrage, mais un seul peut être actif à la fois.
Bien sur, Sieve permet de faire beaucoup de choses, avec gestion de conditions, variables, etc… Ce sera l’occasion de faire un article complet (ou presque) sur Sieve un peu plus tard.
Comme je l’ai dis, l’option mail_debug = yes permet de voir de suite dans le fichier de log /var/log/mail.log c e qui ne va pas.
Pour rajouter la gestion du quota, il suffit de quelques manipulations. Pour rappel, si le champ dans le ldap est égal à zéro, cela veut dire pas de quota. Notez également que le champ est exprimé en bytes.
Dans le fichier /etc/dovecot/conf.d/10-mail.conf on va modifier :
[...]
mail_plugins = $mail_plugins quota
[...]
Dans le fichier /etc/dovecot/conf.d/20-imap.conf :
[...]
mail_plugins = $mail_plugins imap_sieve imap_quota
[...]
Puis dans le fichier 20-lmtp.conf :
[...]
mail_plugins = $mail_plugins sieve quota
[...]
Et pour terminer on remplace le contenu du fichier /etc/dovecot/conf.d/90-quota.conf par ce qui suit :
plugin {
quota = maildir:User quota
quota_warning = storage=90%% quota-warning 90 %u
}
service quota-warning {
executable = script /etc/dovecot/quota.sh
user = vmail
unix_listener quota-warning {
user = vmail
}
}
Voila, c’est en place.
On va rajouter le petit script qui va envoyer le mail d’alerte.
Dans un fichier /etc/dovecot/quota.sh mettez cela :
#!/usr/bin/env bash
PERCENT=${1}
USER=${2}
cat << EOF | /usr/lib/dovecot/dovecot-lda -d $USER -o "plugin/quota=maildir:User quota:noenforcing"
From: no-reply@domaine1.fr
Subject: HOHOHO: Votre BAL est pleine a ${PERCENT}
Content-Type: text/plain; charset="utf-8"
HOHOHO
Votre BAL est pleine a ${PERCENT}. Faut faire du menage mon coco !
EOF
Rien de bien compliqué.
On s’occupe des permissions :
# chmod +x /etc/dovecot/quota.sh
# chown vmail /etc/dovecot/quota.sh
L’œil attentif remarquera que l’on fait appel à dovecot-lda pour ce mail. J’ai tenté avec le lmtp, où pourtant -d a la même utilité, mais je me mange une erreur. Tant pis, au final, lda est toujours dispo, et n’est invoqué qu’au besoin. Autant dire que ça ne va pas beaucoup tourner
On édite le fichier /etc/dovecot/conf.d/15-lda.conf pour tout remplacer par :
protocol lda {
info_log_path =
log_path =
mail_plugins = sieve quota
postmaster_address = postmaster@domaine1.fr
quota_full_tempfail = yes
}
On recharge Dovecot :
# dovecot reload
Si vous voulez ajouter un quota à un utilisteur pour tester, sur le ldap, un fichier mod_quota.ldif :
dn: uid=toto,ou=people,dc=debugo,dc=fr
changetype: modify
replace: mailaccountquota
mailaccountquota: 2147483648
Que vous injectez :
# ladd -f mod_quota.ldif
La, il est réglé à 2Go.
Ensuite, de retour sur le serveur mail, on va déja regarder si le quota est fonctionnel :
# doveadm quota get -u toto@domaine1.fr
doit retourner quelque chose qui ressemble à ca :
Quota name Type Value Limit %
User quota STORAGE 125786 2097152 5
User quota MESSAGE 2329 -
On va aussi tester le script :
./quota.sh 90 toto@domaine1.fr
Et pour tester en conditions réelles, attention, il faut savoir que le mail n’est envoyé qu’une seule fois, au moment où le quota est dépassé.
Par exemple, si vous activez le quota avec une bal deja hors quota vous n’aurez jamais le mail. Du coup, pour tester, c’est pas évident… faut jouer avec une toute petite bal. Mais si les deux commandes au préalable fonctionnent sans problemes, ca doit marcher en production.
Pour voir le quota avec Thunderbird, je conseille Display Quota.
Voila pour cette troisième partie où nous avons fait connaissance avec Dovecot. Je pourrais vous parler en profondeur de la commande doveadm qui permet de faire pas mal de choses mais ce sera pour un tuto annexe… En attendant, rien ne vous empêche de vous documenter.
Vous voulez la bonne nouvelle ? Notre serveur de messagerie est opérationnel.
Pour tester, rien de tel qu’un client lourd. Thunderbird pour Windows, Evolution ou autres pour Linux.
Vous devez pouvoir recevoir et envoyer des mails.
Attention cependant, aucune protection contre le spam n’est encore en place à ce niveau. De la meme façon, vos mails envoyés vers certains domaines (gmail, hotmail) risquent fort de se retrouver classés comme spams (DKIM, SPF et DMARC pas encore en place).
Et oui, j’ai dis opérationnel, pas terminé ! Mais ne ne perdez pas espoir, on a fait le plus dur.
Maintenant, dans la partie IV, nous allons optimiser un peu Postfix.
La partie II, consacrée à Postfix laisse dans notre configuration une potentielle future faille.
Vous le savez, un SMTP externe communiquera avec le votre via le port 25, mais imaginons qu’un instant, un serveur se connecte à vos ports 465 ou bien 587…
Et bien, il ne sera pas embêté. Au final, pour le moment, ce n’est pas bien méchant car il suivra les restrictions qu’il aurait rencontré via le port 25, mais si nous mettons en place des restrictions différentes selon les services (et c’est ce que nous ferons plus tard), et bien, on risque d’avoir des surprises.
Autant y remédier de suite en bloquant la possibilité à un serveur SMTP de se connecter la ou il ne doit pas.
On édite le fichier /etc/postfix/master.cf :
[...]
submission inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
smtps inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_wrappermode=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
[...]
Pour ces deux services, la directive smtpd_client_restriction du main.cf est remplacée : on permet les utilisateurs connectés et on rejette le reste.
Derrière ce terme, se cache quelque de tout simple : le fait de pouvoir modifier (forger) sans vergogne l’adresse de l’expéditeur. Je m’explique :
•.Depuis votre logiciel de messagerie, si vous modifiez l’adresse d’expéditeur par nimportequoi@domaine1.fr, le mail est expédié sans aucun soucis.
•.De la même façon, un MX distant peut tout à fait présenter un mail auprès de notre serveur avec un FROM TO : toto@domaine1.fr , sans que cela ne gène le moins du monde.
On va donc rajouter une restriction au moment de la vérification du sender afin de limiter tout cela.
On édite le fichier /etc/postfix/main.cf et on ajoute dans la directive smtpd_sender_resctriction :
smtpd_sender_restrictions =
reject_sender_login_mismatch,
permit_mynetworks,
[...]
Cette nouvelle directive s’appuie sur une sender_login_maps, qu’on va déclarer plus bas :
smtpd_sender_login_maps = ldap:/etc/postfix/ldap/virtual_senders.cf
On va créer le fichier qui va faire le lien avec le ldap : /etc/postfix/ldap/virtual_senders.cf :
server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = dc=debugo,dc=fr
scope = sub
query_filter = (|(&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES))(&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES)))
result_attribute = mail mailaliasto
Simple, cela retourne le propriétaire de la boite demandée si il y en a un.
Ensuite, deux cas de figures :
•.Si le client est SASL, il faut qu’il soit le propriétaire du mail pour que le mail soit accepté.
•.Si le client n’es pas en SASL et que la boite a un propriétaire, le mail ne sera pas accepté.
Vite fait, je reviens bien sur la distinction TLS et SASL :
•.Client SASL veut dire que le client est authentifié : un utilisateur.
•.Client Non SASL veut dire que c’est un client non authentifié, un serveur MX.
A ne pas confondre avec TLS (ou SSL) qui est la sécurité appliquée à la connexion.
On recharge Postfix :
# postfix reload
Imaginons que dans notre schéma LDAP, nous ayons un attribut mailaliassend qui stipule si un alias a le droit ou non d’envoyer des mails. Après tout, pourquoi pas…
Notre fichier /etc/postfix/ldap/virtual_senders.cf pourrait ressembler à cela :
server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = dc=debugo,dc=fr
scope = sub
query_filter = (|(&(mailaliasfrom=%s)(objectClass=mailaliasdebugo)(mailaliasactif=YES)(mailaliassend=YES))(&(mail=%s)(objectClass=mailaccountdebugo)(mailaccountactif=YES)))
result_attribute = mail mailaliasto
La puissance du LDAP, tout simplement…
Dans sa grande générosité au niveau de ses possibilités, Postfix permet également d’effectuer des vérifications d’accès à l’aide de quatre contrôles :
•.check_client_access
•.check_helo_access
•.check_sender_access
•.check_recipient_access
Dans le cadre du renforcement de notre serveur Postfix, seul check_sender_access sera vraiment obligatoire, les autres, c’est au cas pas cas.
Ces vérification s’appuient sur des données formatées de la sorte :
111.111.111.111 REJECT
// ou bien
toto@domaine1.fr OK
Bien que le OK soit implicite (si pas d’entrée, c’est OK par défaut), il peut être nécessaire dans certains cas de l’expliciter.
Au niveau des actions possible, nous trouvons entre autres :
•.DUNNO: On ne fait rien (sort du contrôle en cours et permet d’éviter un éventuel match avec une règle plus bas…)
•.HOLD: le mail reste dans la queue de Postfix.
•.REDIRECT: redirection du mail vers une autre adresse.
•.etc…
Plus de détails ici : http://www.postfix.org/access.5.html
Si vous utilisez des fichiers statiques, après chaque modification, il faudra invoquer :
# postmap /etc/postfix/nomdufichier
Et pour rappel, vu notre configuration actuelle, ces quatre contrôles se font dans un sens (mail entrant) et dans l’autre (mail sortant).
Chacun de ces contrôles prendra place ensuite dans son bloc smtpd_*_restrictions correspondant.
Ici, on peut autoriser ou interdire des IPs ou des domaines spécifiques.
Exemple :
111.222.111.222 REJECT
domaineabloquer.com REJECT
Et cela se place de la sorte :
smtpd_client_restrictions =
check_client_access hash:/etc/postfix/acces_client,
[...]
Pour filtrer des lourds (spammeurs, bots, etc…), ce n’est pas forcement la meilleure solution. D’une, il faut que la la liste d’accès soit maintenue à jour, et c’est alors un travail quotidien, ou presque…
Seconde « limitation », même en cas de Reject, la session SMTP ira jusqu’au RCPT ou bien sur, elle sera terminée, mais on a gaspillé de la ressource à aller si loin.
On peut demander à Postfix d’arrêter la communication dès qu’une restriction s’applique (en mettant l’option smtpd_delay_reject = no) mais pour trouver un éventuel soucis par la suite, ce peut être gênant. Autre problématique, certains clients gèrent mal une connexion coupée de la sorte…
Je conseille donc de laisser comme c’est par défaut.
Et donc pour bloquer des IPS spécifiques, je passe soit par mon firewall, soit par Postscreen (qu’on verra plus tard).
Ici est effectué un contrôle sur le helo. Comme pour le client, c’est vite compliqué de maintenir quelque chose à jour.
Cependant, on peut quand même effectuer un petit contrôle de routine pour éviter le helo qui serait le notre, ça ne mange pas de pain…
smtpd_helo_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
check_helo_access ldap:/etc/postfix/ldap/check_helo_domains_reject.cf,
[...]
Et le fichier /etc/postfix/ldap/check_helo_domains_reject.cf correspondant :
server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = ou=mail,dc=debugo,dc=fr
scope = sub
query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))
result_attribute = maildomain
result_filter = REJECT Menteur
Rien de sorcier…
On pense à recharger Postfix :
# postfix reload
La, on peut contrôler le destinataire :
Par exemple :
toto@domaine.fr REJECT
Pour bloquer les mails destiné a mon utilisateur toto. Oui, c’est pas franchement utile…
Ou bien encore :
adresseextene@gmail.com REJECT
Pour bloquer les mails à destination de cette adresse. L’intérêt la aussi, dans notre cas de figure, est faible, mais ça existe et ça peut servir.
Ici, on va effectuer un contrôle au niveau de l’expéditeur et on va revenir sur l’antiforge dont je parlais avant pour s’intéresser à un cas que je n’ai pas traité :
Imaginons un serveur SMTP qui nous envoie un mail avec comme FROM TO un mail du genre userbidon@domaine1.fr, la bal n’appartenant à personne, le reject_sender_login_mismatch qu’on a vu plus haut ne bloquera rien, le mail passera.
On va donc y remédier. L’idée étant d’autoriser en FROM TO nos mails qui existent et de rejeter le reste.
Dans le bloc smtpd_sender_resctrictions, nos usagers sont déjà autorisés via permit_sasl_authenticated, on va donc ajouter juste après la restriction pour nos domaines.
On aurait alors besoin d’un fichier ressemblant à ça :
@domaine1.fr REJECT
@domaine2.fr REJECT
Et comme on a le Ldap pour alimenter cela, on va donc passer par un fichier nommé /etc/postfix/ldap/check_sender_domains_reject.cf :
server_host = ldap://ip.ldap
version = 3
bind = yes
bind_dn = cn=viewer,ou=system,dc=debugo,dc=fr
bind_pw = passview
search_base = ou=mail,dc=debugo,dc=fr
scope = sub
query_filter = (&(maildomain=%s)(objectClass=maildomaindebugo)(maildomainactif=YES))
result_attribute = maildomain
result_filter = REJECT Ho le vilain....
Et cela se place de la sorte dans le fichier /etc/postfix/main.cf :
smtpd_sender_restrictions =
reject_sender_login_mismatch,
permit_mynetworks,
permit_sasl_authenticated,
check_sender_access ldap://etc/postfix/ldap/check_sender_domains_reject.cf,
[...]
L’ordre est important. Si le check_sender_access est positionné avant le permit_sasl_authenticated, nos propres utilisateurs ne pourraient pas envoyer de mails.
On recharge :
# postfix reload
Et voila l’antiforge amélioré.
Dernière série de contrôle que l’on peut effectuer ou l’on va regarder un peu plus profondément dans le mail.
Postfix nous propose plusieurs types de contrôles sur les headers :
•.header_check : contrôle dans le header (format ASCII)
•.mime_header_check : contrôle dans le header (format MIME)
•.body_header_check : contrôle dans corps.
•.etc…
Plus de détails ici : http://www.postfix.org/header_checks.5.html
Pour les utiliser, il faut tout d’abord installer le module pcre de Postfix :
# apt-get install postfix-pcre
On recharge Postfix :
# postfix reload
A partir de maintenant, on va pouvoir inspecter, via des REGEX, ce qu’il y a dans les mails.
La syntaxe est la suivante :
/^Subject:.*viagra*/ REJECT Pas besoin, merci
/^From: *toto*/ REJECT On connait la blague
De mon avis et expérience, pour filtrer le spam, ce n’est plus vraiment la meilleure solution sauf cas particulier. Compliqué de maintenir un truc à jour, risque d’un regex un peu foireux qui pourrait être trop restrictif…
Pour information, il est possible de tester vos regex de la sorte :
# postmap -q "Subject: viagra" pcre:/etc/postfix/header_checks
Cela doit vous renvoyer la règle qui s’applique.
Si vous voulez tester avec un mail sauvegardé dans un fichier :
# postmap -q - pcre:/etc/postfix/header_checks < mail.txt
Le second – après le -q est important.
Donc pour le traitement du spam, on fait mieux, cependant, je me sers du header_check pour deux choses.
Créons d’abord le répertoire qui va accueillir nos fichiers :
# mkdir /etc/postfix/check/
Au niveau filtrage en entrée, pour la démonstration, je ne montre qu’un exemple simple. A vous après de faire vos propres règles.
Créons un fichier /etc/postfix/check/header_checks_in avec ce qui suit :
/^s*Content.(Disposition|Type).*names*=s*"?(.+.(bat|exe|com|scr|vbs))"?s*$/ PREPEND X-DEBUGO:WARN
Ici, un header perso X-DEBUGO: WARN est ajouté si le mail contient un fichier avec les extensions bat, exe, com, etc… Celui ci pourra me servir à effectuer un filtre avec Sieve.
Au niveau des actions, on retrouve peu ou prou ce qu’on avait pour les contrôles d’accès. On peut donc aussi utiliser REJECT pour le rejeter, REDIRECT xxx@domaine1.fr , etc…
Voila pour les contrôles en entrée.
L’autre utilité est de pouvoir masquer certaines informations de vos mails sortants, tel que votre IP d’envoi, votre client mail… Par défaut, les headers ajoutés par votre client de messagerie sont un peu trop causant…
Si on regarde ces fameux headers d’un mail qui partirait de chez vous vers un destinataire externe, le premier Received ressemblerait à cela :
Received: from [monip] (monreverse[monip])
(using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits))
(No client certificate requested)
by mail.domaine1.fr (Postfix) with ESMTPSA id 3AB4D22938
for <destinataire@destination.com>; Mon, 21 Jul 1969 02:56:20 +0000 (UTC)
Au passage, pour lire les headers d’un mail, il faut commencer par le bas. Le premier Received que l’on voit en haut est en fait le dernier SMTP rencontré, celui du destinataire.
Et donc notre destinataire, s’il est un peu curieux, peut connaitre notre IP. Puis s’il descend un peu, il en apprendra davantage sur votre OS, etc…
Hum, ce n’est pas terrible…
Allez, nettoyons tout cela !
Dans un fichier /etc/postfix/check/header_checks_out :
/^\s*Received: from \S+ \(\S+ \[\S+\]\)(.*)/ REPLACE Received: from [127.0.0.1] (localhost [127.0.0.1])$1
/^X-Originating-IP:/ IGNORE
/^X-Mailer:/ IGNORE
/^Mime-Version:/ IGNORE
/^User-Agent:/ IGNORE
Au passage, on rencontre souvent sur internet ce regex :
/^Received:.*with ESMTPSA/ IGNORE
En lieu et place de celui que je vous ai indiqué. Celui ci est un peu trop violent à mon gout, vu qu’il supprime complétement le Received from vous concernant. Il peut toujours être utile d’indiquer que vous étiez en tls, le serveur qui a reçu le mail, etc… Je préfère donc juste masquer l’ip d’origine.
Si on indique ces checks dans le main.cf avec :
header_checks = pcre:/etc/postfix/check/header_checks_in,pcre:/etc/postfix/check/header_checks_out
mime_header_checks = pcre:/etc/postfix/check/header_checks_in,pcre:/etc/postfix/check/header_checks_out
Ils vont se faire sur les mails qui entrent et qui sortent. Et on ne veut pas effacer les headers des mails qui nous arrivent… ni ajouter un éventuel header au mail que l’on envoie.
Que faire…
La solution élégante est de faire appel au process cleanup et d’en faire deux « sous process ». Chacun en charge d’un traitement, et affecté comme il faut.
Pour se faire, c’est assez simple :
On édite le fichier /etc/postfix/master.cf pour y ajouter pour chaque service un nouveau service cleanup :
smtp pass - - y - - smtpd
-o cleanup_service_name=subcleanin
[...]
submission inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o cleanup_service_name=subcleanout
smtps inet n - y - - smtpd
-o smtpd_tls_security_level=encrypt
-o smtpd_tls_wrappermode=yes
-o smtpd_client_restrictions=permit_sasl_authenticated,reject
-o cleanup_service_name=subcleanout
Et plus bas, en dessous du cleanup existant, on ajoute :
cleanup unix n - y - 0 cleanup
subcleanout unix n - - - 0 cleanup
-o header_checks=pcre:/etc/postfix/check/header_checks_out
-o mime_header_checks=pcre:/etc/postfix/check/header_checks_out
subcleanin unix n - - - 0 cleanup
-o header_checks=pcre:/etc/postfix/check/header_checks_in
-o mime_header_checks=pcre:/etc/postfix/check/header_checks_in
Précisez bien header_checks et mime_header_checks : les headers pouvant être dans le format MIME ou ASCII, il est important de bien traiter les deux cas.
On recharge Postfix :
# postfix reload
Et voila !
Voila qui termine cette première partie sur l’optimisation de Postfix.
J’ai ai profité pour vous montrer quelques astuces et vous initier à la toute puissance de Postfix.
Je vous invite bien évidement à consulter la doc officielle qui vous permettra de trouver réponses à vos cas particuliers. Bien sur, vous pouvez aussi poser vos questions ici même dans les commentaires.
Allez, courage, on a bientôt terminé ! Dans la partie V, nous allons encore ajouter deux petits modules à Postfix : Policy Spf et Postscreen.
Nous allons ajouter Polycyd SPF et Postscreen, deux outils bien pratiques dans la lutte contre le spam.
SPF (Sender Policy Framework) est un mécanisme simple qui permet de savoir si un SMTP à l’origine d’un mail est bien légitime .
Cela s’appuie sur un enregistrement TXT dans le DNS qui ressemble à ça :
"v=spf1 ip4:ip.legitime mx -all"
Cet enregistrement stipule quel MX est autorisé à envoyer depuis le domaine.
Ici, on va mettre en place la vérification pour les mails entrants, la création dans notre DNS de notre propre SPF se fera dans la partie VII.
On commence en installant le module SPF python (il existe aussi une version perl, mais celle en python est mieux maintenue et nécessite moins de dépendances, puis le python, c’est la vie !)
# apt-get install postfix-policyd-spf-python
Il se configure dans le fichier /etc/postfix-policyd-spf-python/policyd-spf.conf ou vous indiquez ceci :
debugLevel = 1
HELO_reject = Fail
Mail_From_reject = Fail
PermError_reject = False
TempError_Defer = False
skip_addresses = 127.0.0.0/8,10.0.0.0/8
Les mails qui ne respectent pas les SPF seront rejetés. Par contre, s’il n’y a pas de SPF définis, on accepte (les refuser ici est une mauvaise idée, nombre de domaines légitimes n’ont pas de SPF en place…)
Ensuite, dans le fichier /etc/postfix/master.cf on va ajouter en bas :
policyd-spf unix - n n - - spawn
user=nobody argv=/usr/bin/policyd-spf
Et dans le /etc/postfix/main.cf, on ajoute tout d’abord une ligne :
policyd-spf_time_limit = 3600s
puis en dessous, dans le bloc smtpd_sender_restrictions, on ajoute :
smtpd_sender_restrictions =
permit_mynetworks,
permit_sasl_authenticated,
check_sender_access ldap://etc/postfix/ldap/check_sender_domains_reject.cf,
check_policy_service unix:private/policyd-spf,
[...]
On recharge :
# postfix reload
Dorénavant, chaque mail entrant subira une vérification SPF. On pourra l’observer en regardant les headers d’un mail qu’on reçoit :
Received: from mail.domaine1.fr
by mail (Dovecot) with LMTP id N59BECWohFzNVwAAZU03Dg
for <toto@domaine1.fr>; Mon, 21 Jul 1969 02:56:20 +0000
Received-SPF: Pass (mailfrom) identity=mailfrom; client-ip=blablabla...
Voila pour le contrôle SPF qui va permettre d’écrémer un peu plus.
On arrive à la chose la plus efficace pour lutter contre le spam bête et méchant. S’il ne devait en rester qu’un, ce serait lui je pense. Pourtant il ne réinvente rien et utilise des principes déjà connus, mais il le fait bien et simplement.
Il est le bouclier contre les zombies/bots, etc… que je résume en « les lourds »…
Il est… Postscreen !
Postscreen étant intégré dans Postfix, rien à installer, il suffit de l’activer.
Dans le fichier /etc/postfix/master.cf, commentez la ligne :
smtp inet n - y - - smtpd
et décommentez juste en dessous :
smtp inet n - y - 1 postscreen
smtpd pass - - y - - smtpd
dnsblog unix - - y - 0 dnsblog
tlsproxy unix - - y - 0 tlsproxy
Le reste de la configuration se passera dans le fichier /etc/postfix/main.cf.
Postcreen peut faire deux types de contrôles :
•.des contrôles simples
•.des contrôles profonds
Les contrôles simples se fond avant de passer la main à Postfix. Si tout est Ok, le mail suit son chemin.
Au contraire, les contrôles profonds prennent la main sur l’ensemble du dialogue et introduisent de par ce fait, un greylisting. J’y reviens plus bas.
Pour chaque contrôle, on peut définir une action :
•.ignore : on ne fait rien. Peut servir en cas de debug.
•.enforced : le blocage est actif, mais la coupure se fera au moment du RCPT TO: avec une réponse 550 5.3.2 Service currently unavailable
•.drop : efficace, on coupe court avec une réponse 521 5.3.2 Service currently unavailable
Un serveur qui sera accepté sera mis en liste blanche pour les prochaines fois afin de ne pas mobiliser de la ressource pour rien.
Simples ne veut pas dire inefficaces. Personnellement, je n’utilise qu’eux, n’aimant pas le principe du greylisting.
Simplissime, ce contrôle va permettre de bloquer des IPs et contrairement au blocage dans Postfix, ici avec l’action sur drop, c’est immédiat. Ciao !
Pour l’activer, ajoutez ces lignes dans le fichier /etc/postfix/main.cf :
postscreen_access_list = permit_mynetworks, cidr:/etc/postfix/postscreen_access.cidr
postscreen_blacklist_action = drop
Le fichier /etc/postfix/postscreen_access.cidr doit ressembler à cela :
xxx.xxx.xxx.xxx reject
[...]
Ce contrôle joue sur une subtilité du protocole SMTP. En effet, si le serveur répond avec « 250-On attend un pneu…« , le tiret après le 250 indique qu’il y a plusieurs lignes.
Et il attend le temps indiqué avant d’envoyer le « 250 mail.domaine1.fr ESMTP mail (Debian/GNU)« .
Du coup, un zombie trop rapide se fera avoir, et hop, dehors !
Pour l’activer, ajoutez ces lignes dans le fichier /etc/postfix/main.cf :
postscreen_greet_wait = 3s
postscreen_greet_banner = On attend un pneu...
postscreen_greet_action = drop
Le temps d’attente sert également à Postscreen pour consulter les Dnsbl qu’on voit juste en dessous.
Ici, on va interroger des RBL.
Le principe est simple. On passe par une interrogation DNS pour savoir si un MX distant est légitime ou non.
Une réponse du genre 127.0.0.X indique qu’il ne faut pas accepter le mail (le type de réponse dépend de la liste dans la quelle se trouve l’IP). On peut éventuellement ne prendre que certaines réponses.
Pour l’activer, ajoutez ces lignes dans le fichier /etc/postfix/main.cf :
postscreen_dnsbl_sites =
zen.spamhaus.org*2,
bl.spamcop.net,
b.barracudacentral.org*2
postscreen_dnsbl_threshold = 3
postscreen_dnsbl_action = drop
J’utilise trois listes. En mettre de trop n’est pas forcement une bonne idée, temps d’interrogation plus long, trouver comment bien pondérer chacune…
Sachez cependant qu’il en existe plein. Vous en trouverez ici par exemple : https://www.dnsbl.info/dnsbl-list.php
Pour faire une interrogation à la main, si votre IP est AAA.BBB.CCC.DDD :
# dig +short DDD.CCC.BBB.AAA.b.barracudacentral.org
On passe par un PTR record, ce qui fait qu’on peut connaitre « l’état » d’une IP en interrogeant n’importe quel DNS, ce dernier ira faire la requête au bon endroit.
Si pas de retour, l’IP n’est pas blacklisté, si retour, IP blacklisté donc.
Très efficace contre les « lourds » qui ne respecte pas le protocole SMTP, ces vérifications ont cependant un inconvénient comme je l’expliquais :
Ils introduisent un Greylisting. Pour effectuer ces vérifications, Postscreen prend en charge tout la communication SMTP, mais le bougre à la fin n’est pas capable de repasser la main à Postfix.
Postscreen règle le problème très « simplement » en répondant à la fin : 450 4.3.2 Service currently unavailable et en mettant au passage le serveur en liste blanche.
Le voila le Greylisting … Un serveur SMTP bien configuré se doit de retenter l’envoi et comme il sera reconnu par Postscreen, ce dernier passera la main à Postfix.
Ça, c’est la théorie… Les trucs configurés avec les pieds, on en voit partout et il est tout a fait possible que le SMTP distant, bien que légitime, ne retente jamais. C’est pourquoi je n’aime pas le principe du Greylisting.
A vous de voir comme vous le sentez …
Postscreen ne gérant pas le pipelining (du full duplex en quelque sorte), il l’indique durant la communication. Un client « correct » le prendra alors en compte. Un « lourd », certainement que non, et bam !
postscreen_pipelining_enable = yes
postscreen_pipelining_action = enforce
Contrôle sur d’éventuelles commandes CONNECT, GET et POST utilisées par les « lourds » passant par des proxys.
postscreen_non_smtp_command_enable = yes
postscreen_non_smtp_command_action = enforce
La norme SMTP impose que chaque ligne se terminer par <CR><LF>. Les « lourds », souvent, n’utilisent que <LF>.
postscreen_bare_newline_enable = yes
postscreen_bare_newline_action = enforce
Voila pour ces petits ajouts à Postfix. Ils sont simples, mais efficaces comme vous pouvez le voir.
Avec tout le travail abattu jusque la, Rspamd que l’on va maintenant installer dans la partie VI va se sentir léger.
Le paquet Rspamd disponible dans les dépôts de Debian n’étant plus maintenu, on va passer par les dépôts de Rspamd
# wget -O- https://rspamd.com/apt-stable/gpg.key | apt-key add -
La, si un message évoque un problème de certificats, c’est que le paquet ca-certificates n’est pas présent.
# echo "deb [arch=amd64] http://rspamd.com/apt-stable/ stretch main" > /etc/apt/sources.list.d/rspamd.list
# apt-get update
# apt-get install rspamd
Pour fonctionner, Rspamd a besoin d’un serveur redis. Perso, j’ai une VM dédiée à cela, mais ici, on va l’installer sur le serveur mail.
# apt-get install redis-server
Nous verrons dans un article plus tard l’installation d’un serveur redis « général ».
Pour la configuration initiale, un assistant est disponible, ne nous en privons pas :
# rspamadm configwizard
Puis répondez :
Do you wish to continue?[Y/n]: -> Yes
Controller password is not set, do you want to set one?[Y/n]: -> Yes (et vous le renseignez)
Do you wish to set Redis servers?[Y/n]: -> Yes
Input read only servers separated by `,` [default: localhost]: (si server Redis sur un autre serveur, vous indiquez son ip.)
Input write only servers separated by `,` [default: localhost]: (idem)
Do you have any password set for your Redis?[y/N]: si y'a un pass, vous l'indiquez
Do you have any specific database for your Redis?[y/N]: s'il faut spécifier une base (dans le cas d'un redis central), vous la spécifiez aussi
Do you want to setup dkim signing feature?[y/N]: -> No (on le fera après)
Expire time for new tokens [100d]: on laisse par défaut.
Reset previous data?[y/N]: -> No, vu qu'il n'y en a pas
Do you wish to convert them to Redis?[Y/n]: -> Yes
Et on termine en rechargeant :
# service rspamd reload
Au niveau de la configuration, tout se passe dans /etc/rspamd/, cependant, modifier ces fichiers n’est pas une bonne idée car comme indiqué dedans, ils se retrouveraient écrasés en cas d’update. On va donc utiliser le répertoire /etc/rspamd/local.d pour y indiquer nos modifications.
Ce fichier est créé par l’assistant, il suffit de rajouter la première ligne
autolearn = true;
backend = "redis";
new_schema = true;
expire = 8640000;
Fichier également créé par l’assistant. Ici, on rajoute les deux lignes pour les sockets. Le socket sur le port 11334 sera pour l’interface Web (c’est pour cela qu’on le bind sur l’ip interne de la machine et non sur localhost). Le second socket servira pour l’apprentissage des spams.
password = trucavous
bind_socket = "ip.interne:11334";
bind_socket = "/var/run/rspamd/rspamd.sock mode=0666 owner=nobody";
Fichier à créer. Il permet d’indiquer vos valeurs pour les différentes actions.
actions {
add_header = 5;
greylist = 25;
reject = 50;
}
A vous de bien régler ces paramètres. Ici, le reject est volontairement haut, dans un but de test et pour pouvoir le baisser au fur et à mesure.
Ce fichier est à créer. Il indique d’ajouter des entêtes dans les mails. Grace à eux, vous pourrez voir directement dans votre logiciel ce qui a provoqué ou non le marquage en spam. Mettez simplement :
extended_spam_headers = true;
Dernier fichier à créer. Permet à Rspamd de se mettre à jour automatiquement au niveau des règles. On l’active, tout simplement :
enabled = true;
Et voila pour la configuration de Rspamd. Il existe d’autres modules, mais nous en parlerons dans un futur article ou nous approfondirons le sujet sur Rspamd.
Pour dire à Postfix de passer le mail à Rspamd, c’est le protocole milter que l’on va utiliser en indiquant en bas de notre fichier /etc/postfix/main.cf :
milter_protocol = 6
milter_default_action = accept
smtpd_milters = inet:localhost:11332
non_smtpd_milters=inet:localhost:11332
milter_mail_macros = i {mail_addr} {client_addr} {client_name} {auth_authen}
Le milter_default_action spécifie l’action par défaut au cas ou Rspamd ne serait pas disponible. On recharge :
# postfix reload
# service rspamd restart
Pour l’utilisation de Rspamd au quotidien, pas grand chose à faire. C’est automatique, même pour les mises à jour. Cependant, si vous avez déjà un corpus de spam et de ham à lui apprendre, ce n’est pas une mauvaise chose de commencer par la, le filtre bayésien ne fonctionnant pas à moins de 200 mails appris par catégorie. Pour se faire, j’ai toujours deux dossiers récents de spams et de hams que je garde sous le coude. Je les déplace dans ma bal dans deux répertoires. Puis pour le spam :
# rspamc -h /var/run/rspamd/rspamd.sock learn_spam /home/vmail/domaine1.fr/toto/mailbox/.Spamtolearn/
et pour le ham :
# rspamc -h /var/run/rspamd/rspamd.sock learn_ham /home/vmail/domaine1.fr/toto/mailbox/.Hamtolearn/
Pour regarder ensuite les statistiques et voir à combien on en est :
# rspamc -h /var/run/rspamd/rspamd.sock stat
Pour un bon apprentissage, il faut lui apprendre des spams certes, mais également des hams, c’est important.
Couplé avec Dovecot, Rspamd nous propose de pouvoir apprendre également en fonction des actions des utilisateurs. Si un mail est déplacé vers le répertoire spam, il sera appris comme tel et au contraire, s’il est sorti du répertoire Spam vers autre chose que la corbeille, il sera appris comme Ham. Dans le fichier /etc/dovecot/conf.d/90-sieve-extprograms.conf, mettez cela :
plugin {
sieve_plugins = sieve_imapsieve sieve_extprograms
imapsieve_mailbox1_name = Junk
imapsieve_mailbox1_causes = COPY
imapsieve_mailbox1_before = file:/etc/dovecot/sieve/report-spam.sieve
imapsieve_mailbox2_name = *
imapsieve_mailbox2_from = Junk
imapsieve_mailbox2_causes = COPY
imapsieve_mailbox2_before = file:/etc/dovecot/sieve/report-ham.sieve
sieve_pipe_bin_dir = /etc/dovecot/sieve
sieve_global_extensions = +vnd.dovecot.pipe
}
On recharge Dovecot :
# dovecot reload
Quand un mail sera déplacé dans le répertoire Junk (Spam), le filtre report-spam.sieve sera appelé. Quand un mail sera déplacé depuis le répertoire Junk vers un autre répertoire (autre que la Corbeille), le filtre report-ham.sieve sera appelé. On va créer les filtre sieves. On créer un répertoire :
# mkdir /etc/dovecto/sieve/
Puis un fichier /etc/dovecot/sieve/report-spam.sieve :
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.email" "*" {
set "email" "${1}";
}
pipe :copy "train-spam.sh" [ "${email}" ];
puis, /etc/dovecot/sieve/report-spam.sieve :
require ["vnd.dovecot.pipe", "copy", "imapsieve", "environment", "variables"];
if environment :matches "imap.mailbox" "*" {
set "mailbox" "${1}";
}
if string "${mailbox}" "Trash" {
stop;
}
if environment :matches "imap.email" "*" {
set "email" "${1}";
}
pipe :copy "train-ham.sh" [ "${email}" ];
On les compile :
# sievec report-ham.sieve
# sievec report-spam.sieve
Puis on change l’user :
# chown vmail:vmail report-*
On va passer à la création de nos deux petits scripts : Tout d’abord /etc/dovecot/sieve/train-ham.sh :
exec /usr/bin/rspamc -h /var/run/rspamd/rspamd.sock learn_ham
et /etc/dovecot/sieve/train-spam.sh :
exec /usr/bin/rspamc -h /var/run/rspamd/rspamd.sock learn_spam
Et on leur donne les droits :
# chown vmail:vmail train-*
# chmod +x train-*
On recharge Dovecot :
# dovecot reload
Et voila, vous pouvez vérifier en déplaçant un spam ou un ham et voir dans les fichiers de logs : Fichier /var/log/mail.log :
mail dovecot: imap(toto@domaine1.fr): sieve: pipe action: piped message to program `train-spam.sh'
Fichier /var/log/rspamd/rspamd.log :
#9159(controller) <e6896a>; csession; rspamd_controller_check_password: allow unauthorized connection from a unix socket
#9159(controller) <e6896a>; csession; rspamd_message_parse: loaded message; id: <004801d4dc01$02b7a725$5d7532ac$@lourd.com>; queue-id: <undef>; size: 1732; checksum: <b32bcf8d811d92610d2808ce822930dc>
#9159(controller) <e6896a>; csession; rspamd_mime_text_part_utf8_convert: converted from IBM852 to UTF-8 inlen: 104, outlen: 104 (104 UTF16 chars)
#9159(controller) <e6896a>; csession; rspamd_controller_learn_fin_task: </var/run/rspamd/rspamd.sock> learned message as spam: 004801d4dc01$02b7a725$5d7532ac$@lourd.com
Voila une affaire qui roule.
Si jusque la, vous utilisiez Opendkim, vous pouvez l’oublier: Rspamd peut se charger de cette tâche, autant s’éviter une pièce de plus dans notre puzzle.
On va tout d’abord créer le répertoire qui va accueillir nos clés :
# mkdir /var/lib/rspamd/dkim
Créez un fichier /etc/rspamd/local.d/dkim_signing.conf et ajoutez :
path = "/var/lib/rspamd/dkim/dkim.$domain.key";
allow_username_mismatch = true;
Pour signer un nouveau domaine :
# rspamadm dkim_keygen -b 2048 -s dkim -d domaine1.fr -k /var/lib/rspamd/dkim/dkim.domaine1.fr.key | tee -a /var/lib/rspamd/dkim/dkim.domaine1.fr.pub
•.-b indique que l’on veut une clé de 2048 bits.
•.-s est le sélecteur.
•.-d indique le domaine.
•.-k pour dire ou l’on veut stocker la clé privée.
•.et pour terminer, on enregistre la clé publique, qui par défaut est simplement affichée, dans un fichier.
Gardez la clé publique sous le coude, on la rajoutera dans le DNS dans la partie VII. Pour info, il est tout a fait possible d’avoir des sélecteurs différents, soit en fonction des domaines, soit pour versionner, etc… Dans ce cas, il faudrait renseigner le fichier /etc/rspamd/local.d/dkim_signing.conf de la sorte :
path = "/var/lib/rspamd/dkim/$selector.$domain.key";
selector_map = "/etc/rspamd/dkim_selectors.map";
Et le fichier /etc/rspamd/dkim_selectors.map devra contenir :
domaine.fr selecteur
domaine2.fr autre_selecteur
[...]
Puis changeons les droits :
# chmod u=rw,g=r,o= /var/lib/rspamd/dkim/*
# chown _rspamd /var/lib/rspamd/dkim/*
On recharge :
# service rspamd reload
Rspamd propose une interface Web. Avant de la tester, je pensais que c’était un gadget, mais après avoir vu la chose, force est de constater qu’elle est plutôt bien fichue et permet de voir l’historique des messages, ce qui a provoqué ou non leur tag, rejet… On peut aussi y modifier les valeurs de metrics, les symboles (ce qui sert à détecter un spam par rapport à un critère donné). Bref, très pratique, je vous conseille de vous en servir. C’est déjà en écoute sur le port 11334, mais on ne va pas faire le goret et ouvrir cela sur le routeur. Servez vous d’un reverse proxy (Nginx est juste parfait) et indiquez dans la configuration de votre serveur.
location /rspamd/ {
proxy_pass http://ip.interne.mail:11334/;
proxy_http_version 1.1;
}
Pour s’y connecter ensuite : https://www.domaine1.fr/rspamd (par exemple) et le mot de passe est celui qu’on a renseigné grâce à l’assistant.
Voila, Rspamd est installé et opérationnel. La configuration reste simple, mais comme déjà dit, il existe d’autres modules que l’on peut utiliser. Ce sera pour un autre article, hors de la série sur le serveur de messagerie. La configuration présentée ici est bien suffisante dans un premier temps. En attendant, si vous voulez en savoir plus, la documentation officielle est ici : https://rspamd.com/doc/ On va passer à la finalisation de notre architecture mail avec, dans la partie VII, la mise en place des enregistrements SPF, DKIM et DMARC dans notre DNS.
Dans l’idéal, vous gérez vous même votre DNS, sinon, faites les modifications indiquées dans l’interface de votre registar.
Ces trois enregistrements s’appuient sur de simples champss TXT, afin que tous les resolvers les comprennent.
Il fut un temps ou on trouvait un champ SPF mais celui ci a été abandonné car pas vraiment de RFC pour cela. Il est conseillé maintenant de ne faire qu’un enregistrement TXT.
Bref, c’est tout simple, mais c’est vital, du moins, pour votre système de messagerie !
Cet enregistrement va stipuler une ou plusieurs IP(s) que l’ont autorise à envoyer des mails en notre nom.
Dans votre fichier de zone, indiquez :
domaine1.fr. IN TXT "v=spf1 ip4:ipserveurmail mx -all"
On indique d’accepter les mails venant de notre IP et de refuser strictement les autres.
Cet enregistrement indique la clé publique correspondant à la clé privée utilisée par Rspamd pour signer les mails.
Un serveur distant pourra alors vérifier l’authenticité du mail en vérifiant si la clé privée utilisée pour la signature correspond à la clé publique publiée dans le DNS.
Reprenez la clé publique que vous aviez gardé sous le coude dans la partie VI :
dkim._domainkey IN TXT ( "v=DKIM1; k=rsa; "
"p=plein de caracteres eventuellement sur plusieurs lignes" ) ;
Insérez tout cela dans votre fichier de zone, tout simplement.
Ce n’est pas à proprement parlé un système de protection, mais plus une façon de dire ce qu’il faut faire avec des mails qui ne passe pas votre politique SPF et/ou DKIM.
Une consigne pour le SMTP qui reçoit en quelque sorte. A ne pas négliger, car l’absence de ce champ peut compromettre la livraison de vos mails.
Insérez une ligne semblable à la suivante :
_dmarc.domaine1.fr. IN TXT "v=DMARC1; p=none; rua=mailto:postmaster@domaine1.fr;ruf=mailto:postmaster@domaine1.fr"
le p indique la politique à appliquer chez le SMTP si un mail reçu en votre nom (de domaine) ne passe ni SPF, ni DKIM.
Il est possible de spécifier :
•.none, ne rien faire, mais juste le consigner dans les rapports envoyés à postmaster@domaine1.fr
•.quarantine : mettre le mail en spam.
•.reject : le rejeter
rua indique à quelle adresse recevoir les reports agrégés, ruf indique où recevoir les reports détaillés (envoyés à chaque fois qu’un mail en votre nom est refusé)
Pour plus d’informations : https://dmarc.org/wiki
Au début, disons le premier mois, utilisez un p=none et une fois qu’on voit que tout est OK (les mails refusés le sont à juste titre et non pas du à une boulette de votre côté), vous pouvez passer sur p=quarantine, ou p=reject.
Bien sur, une fois ces ajouts faits, on pense à incrémenter le sérial du fichier de zone, puis on recharge bind :
# rndc reload
Pour tester, on va utiliser dig et au passage, l’interrogation se fera auprès du DNS de Google pour être sur que la propagation DNS est bonne.
# dig domaine1.fr TXT @8.8.4.4 +short
Va vous renvoyer les enregistrements TXT, dont le SPF.
# dig dkim._domainkey.domaine1.fr TXT @8.8.4.4 +short
Va vous renvoyer votre DKIM.
# dig _dmarc.debugo.fr TXT @8.8.4.4 +short
Bah, le Dmarc hein…
On peut aussi utiliser des outils en ligne : http://www.appmaildev.com, https://mxtoolbox.com, etc…Il en existe plein d’autres…
Bah voila, ce n’était pas la partie la plus compliquée, mais à partir de maintenant, vous pouvez envoyer des messages en étant clean et reconnu par vos pairs !
Il existe aussi le système ARC, mais nous en parlerons dans un article complémentaire.
Et voila, plus qu’à faire une petite conclusion générale et on en aura fini avec notre serveur de mails.
Et bien voila, on y est. On a enfin terminé de toute mettre en place : Posfix, Dovecot, Rspamd, etc.. tout tourne de concert sans anicroches.
Cependant, quelques derniers conseils…
Dans la partie II, j’active dans la configuration de Postfix les notifications au postmaster (qui est un alias de ma bal principale)
Du coup, pour les ranger proprement, j’utilise un filtre sieve :
if header :contains "subject" "Postfix SMTP server"
{
fileinto "Serveur";
}
De la sorte, je vois les erreurs (dans un dossier à part, pour ne pas polluer ma boite de réception) et peut y remédier (la plus part du temps, ce sont des lourds à bloquer définitivement dans le FW).
Ensuite, il peut être utile de vérifier de temps à autres si vous n’êtes pas en liste noire sur une des nombreuses DNSBL.
Il existe de nombreux sites ou script qui permettent de faire cette vérification.
•.etc…
Si vous vous retrouvez listé, chaque liste gérant la chose à sa façon, à vous d’aller voir sur leur site pour vous faire délister.
Voila quelques liens pour tester un peu votre serveur :
https://www.mail-tester.com : très pratique, permet de voir si vous n’auriez pas louper une étape en vous donnant une note.
https://www.emailsecuritycheck.net : teste la protection de votre système en envoyant 7 mails douteux. Le 3 ne doit même pas arriver, les autres doivent se retrouver en spam.
Plus généralement, le site https://mxtoolbox.com est très complet car il couvre de nombreuses vérifications (et pas qu’au sujet de la messagerie).
Bien évidement, la aussi, il y a pléthore de sites….
La messagerie est un sujet vaste et bien sur, je n’ai pas forcement approfondi certains points (j’avoue, je commence à saturer sur la partie messagerie 😉 )
Cependant, j’y reviendrais un peu plus tard.
Du coup, nous verrons :
•.Fail2ban pour se protéger un peu.
•.Un point sur les restrictions et comment les optimiser.
•.Unbound pour alléger le trafic DNS.
•.Une protection en plus au niveau des Headers.
•.Un complément sur Rspamd.
•.Faire en sorte que nos VMs puissent envoyer les mails systèmes via notre serveur pour les centraliser.
•.Automatiser la vérification des DNSBL.
•.Limitation en envoi au cas ou un compte serait compromis
•.Installation d’un Webmail.
•.etc…
Bref, restez à l’écoute !
Les boulets qui tentent de se connecter à un de vos services, ca peut vite devenir…. pénible.
Avec les fuites de mot de passe qu’on retrouve un peu partout, n’importe qui ou presque peut maintenant faire le Jean-Kevin (mes excuses si un de mes lecteurs s’appelle Jean-Kevin, faudra que je parle à ses parents ceci dit..)
Bref, trêve de plaisanteries, et attaquons nous à ces petits malandrins qui n’ont rien d’autres à faire que de remplir nos fichiers de logs….
Comme on vient de terminer l’installation du serveur de messagerie, on va justement filtrer un peu les tentatives de login infructueuses sur l’IMAP et sur le SMTP.
Au niveau de son fonctionnement, Fail2ban est simple à comprendre.
Tout d’abord, on a des jails, c’est à dire une configuration que l’on créé et qui va s’occuper de surveiller un service en regardant ses logs. Ce sera dans le répertoire /etc/fail2ban/jail.d/.
Pour se faire, il faut savoir quoi chercher de suspect, c’est le rôle des filtres…. La, dans /etc/fail2ban/filter.d/, on en trouve déjà beaucoup de proposés. Bien sur, on pourra faire les siens.
Et ensuite, il faut dire ce qu’on fait avec les lourds que l’on trouve dans les logs après filtrage : ce sont les actions. La aussi, dans /etc/fail2ban/action.d/ on en trouve, et la aussi on pourra faire les nôtres.
Pour l’installation, rien de compliqué :
# apt-get install fail2ban
Maintenant, il s’agit de créer les jails. On va en faire une pour Postfix, puis une pour Dovecot
Dans un fichier /etc/fail2ban/jail.d/postfix.conf, mettez ceci :
[postfix-sasl]
enabled = true
filter = postfix-sasl
action = iptables-allports
mail[name=Postfix SASL]
bantime = 3600
maxretry = 2
logpath = /var/log/mail.log
Au niveau du filtre, on se sert de celui qui existe déjà, et au niveau action, on utilise celle qui bloque tout au niveau du FW plus un p’tit mail d’info.
On active le ban au bout de deux tentatives et ce pour une heure.
Dans un fichier /etc/fail2ban/jail.d/dovecot.conf, mettez ceci :
[dovecot]
enabled = true
filter = dovecot
action = iptables-allports
mail[name=Dovecot]
bantime = 3600
maxretry = 2
logpath = /var/log/mail.log
La, on utilise le filtre dovecot déjà existant et le reste, comme Postfix…
Ne reste plus qu’à recharger :
# service fail2ban reload
Puis, on peut déjà regarder le log voir si tout est OK :
# tail /var/log/fail2ban.log -f
On peut aussi en savoir plus sur les jails en cours :
# fail2ban-client status
Puis le détail :
# fail2ban-client status postfix-sasl
Pour bannir de force par exemple :
# fail2ban-client set postfix-sasl banip XXX.XXX.XXX.XXX
etc….
Après, il n’y a plus qu’à attendre pour voir si cela marche bien, et généralement, ça ne prend pas trop de temps.
Et voila, vous voyez, c’est très simple et ça marche… mais ceci dit, je n’aime pas car chaque serveur aura alors ses propres règles de blocages.
Et perso, si un lourd est lourd sur un service, je ne vois pas pourquoi il ne le serait pas sur un autre, ce serait donc mieux de le bloquer en amont, avec le firewall du routeur.
Et bien, cela tombe bien, c’est ce qu’on va voir dans l’article suivant avec la mise en place d’un système client-serveur en python.
Précédemment, nous avons vu Fail2ban configuré pour Dovecot et Postfix, mais l’inconvénient de la solution proposée dans une architecture de serveurs derrière un routeur, c’est que pour le coup, chaque serveur aura ses propres règles de blocage.
J’aimerais bien centraliser tout. Si un boulet se présente sur le serveur mail, autant le bloquer sur tout et ce, dès son arrivée sur mon routeur…
Du coup, il faut trouver le moyen de faire le blocage directement dans le firewall de ce dernier. Quid ?
Installer fail2ban sur le routeur ? Pourquoi pas, mais il lui faudrait donc la possibilité de lire les logs des autres VMS…
Des partages NFS ? Non…
Rapatrier les logs sur le routeur pour que fail2ban fasse son taf ? Bof, mon routeur n’a pas pour vocation de centraliser les logs…
Hum… Fail2ban sur le routeur n’est pas la solution.
Le truc serait de garder fail2ban sur chaque machine avec ses logs et sa config et de piloter le firewall du routeur…
En voila une bonne idée !
Pour cela, on va passer par un truc que j’affectionne, un petit système client-serveur en python. C’est rapide à mettre en place et ça répond parfaitement à mon problème.
Sur le routeur, un serveur en écoute des instructions des clients pour modifier le firewall. Et sur chaque serveur, un client actionné par fail2ban pour balancer l’ordre.
Simple non ?
Sur le firewall, on va déjà préparer le terrain et créant des chaines spécifiques.
Je pars du principe que vous utilisez un fichier pour les règles du firewall. On va dire qu’il s’appelle firewall.sh.
Donc, dans firewall.sh, après :
#!/bin/bash
iptables -t filter -F
iptables -t filter -X
iptables -t nat -F
iptables -t nat -X
iptables -t mangle -F
iptables -t mangle -X
Ajoutez :
# creation des chaines
iptables -N f2b-postfix
iptables -N f2b-dovecot
# on ajoute un retour dans ces chaines (pour revenir à INPUT ou FORWARD, selon le cas)
iptables -A f2b-postfix -j RETURN
iptables -A f2b-dovecot -j RETURN
# Puis on indique dans INPUT et FORWARD de traverser les nouvelles chaines.
iptables -I INPUT -j f2b-postfix
iptables -I INPUT -j f2b-dovevot
iptables -I FORWARD -j f2b-postfix
iptables -I FORWARD -j f2b-dovecot
[...]
On reprend le concept qu’utilise Fail2ban par défaut, à savoir créer une nouvelle chaine, puis faire passer les flux dedans. Si rien ne bloque, ça revient dans les chaines INPUT ou FORWARD (en fonction) et passe les autres règles.
Et j’en profite pour créer une chaine par service, histoire de bien voir par la suite quel service à fait le blocage.
Au passage pensez à autoriser en INPUT sur le port que vous choisirez pour votre serveur.
iptables -t filter -A INPUT -p tcp -s 10.20.1.0/24 --dport 666 -j ACCEPT
Mon réseau interne entre les vms étant en 10.20.1.0/24
Une fois votre fichier firewall.sh ou autre modifié, on exécute :
routeur# ./firewall.sh
Maintenant, on va créer le serveur python qui va écouter les ordres des autres VMS, et appliquer les règles.
On installe python :
routeur# apt-get install python
Puis dans un fichier : /srv/pyban.py, vous copiez cela :
#!/usr/bin/env python
import socket
import os
import threading
class ClientThread(threading.Thread):
def __init__(self, ip, port, clientsocket):
threading.Thread.__init__(self)
self.ip = ip
self.port = port
self.clientsocket = clientsocket
def run(self):
r = self.clientsocket.recv(1024)
item = r.split(":")
if item[0] == "ban":
chain = "iptables -I "+item[2]+" -s "+item[1]+" -j DROP"
os.system(chain)
if item[0] == "unban":
chain = "iptables -D "+item[2]+" -s "+item[1]+" -j DROP"
os.system(chain)
else:
error = 1
tcpsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
tcpsock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
tcpsock.bind(("XXX.XXX.XXX.XXX",666))
while True:
tcpsock.listen(5)
(clientsocket, (ip, port)) = tcpsock.accept()
newthread = ClientThread(ip, port, clientsocket)
newthread.start()
tcpsock.close()
Tout simple, on a un serveur qui écoute sur le port 666, avec la gestion du multithread, ca ne coute rien.
Il attend comme paramètres ce qu’il faut faire (ban ou unban), l’ip et la chaine dans laquelle on se place.
Pensez bien sur à remplacer XXX.XXX.XXX.XXX par l’ip interne du routeur (par exemple, 10.20.1.1; pas de localhost car sinon, les clients ne pourraient le joindre…)
On peut déjà tester si cela tourne sans erreur :
# python /srv/pyban.py
Ctrl+C pour arrêter.
Maintenant, on va en faire un service, histoire qu’il se lance tout seul et soit autonome.
Créez un fichier /etc/systemd/system/pyban.service et mettez y :
Description=Server Python Ban
After=network-online.target
[Service]
Type=idle
ExecStart=/usr/bin/python /srv/pyban.py
[Install]
WantedBy=multi-user.target
Puis on l’active et on le démarre :
# systemctl enable pyban.service
# systemctl start pyban.service
Voila pour le routeur.
Pour l’exemple, je reprend mon serveur de mail.
Bien évidement, on installe python :
mail# apt-get install python
On va créer ensuite un fichier /srv/pybanclient.py avec dedans :
#!/usr/bin/env python
import socket
import sys
try:
s = ":";
seq = (sys.argv[1], sys.argv[2], sys.argv[3]);
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("XXX.XXX.XXX.XXX", 666))
sock.send(s.join(seq))
sock.close
except(socket.error):
sys.exit()
Bien évidement, XXX.XXX.XXX.XXX doit être remplacé par l’ip du routeur.
On va créer un fichier action nommé /etc/fail2ban/action.d/pyban.conf avec ce qui suit dedans :
[Definition]
actionban = python /srv/pybanclient.py ban <ip> <name>
actionunban = python /srv/pybanclient.py unban <ip> <name>
On va modifier nos deux jails.
Tout d’abord /etc/fail2ban/jail.d/postfix.conf :
[postfix-sasl]
enabled = true
filter = postfix-sasl
action = pyban[name=f2b-postfix]
mail[name=Postfix SASL]
bantime = 3600
maxretry = 2
logpath = /var/log/mail.log
Puis /etc/fail2ban/jail.d/dovecot.conf :
[dovecot]
enabled = true
filter = dovecot
action = pyban[name=f2b-dovecot]
mail[name=Dovecot]
bantime = 3600
maxretry = 2
logpath = /var/log/mail.log
Et on termine en rechargeant :
mail# service fail2ban reload
Rien de plus simple.
Sur le serveur :
serveur# fail2ban-client set postfix-sasl banip XXX.XXX.XXX.XXX
Sur le routeur :
routeur# iptables -L -n
On doit voir l’ip apparaitre dans la bonne chaine avec un DROP devant .
Et si on déban sur le serveur :
serveur# fail2ban-client set postfix-sasl unbanip XXX.XXX.XXX.XXX
Ce doit être nettoyé sur le routeur :
routeur# iptables -L -n
Bah voila, on a enfin notre fail2ban qui peut piloter un FW en amont afin de voir les boulets bloqués sur tous nos services. Rien de bien sorcier au final…
Par la suite, on pourra rajouter d’autres services en pilotage en rajoutant leurs règles dans le FW du routeur et avec des clients python sur les serveurs.